summaryrefslogtreecommitdiff
path: root/doc/rfc/rfc9497.txt
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-11-27 20:54:24 +0100
committerThomas Voss <mail@thomasvoss.com> 2024-11-27 20:54:24 +0100
commit4bfd864f10b68b71482b35c818559068ef8d5797 (patch)
treee3989f47a7994642eb325063d46e8f08ffa681dc /doc/rfc/rfc9497.txt
parentea76e11061bda059ae9f9ad130a9895cc85607db (diff)
doc: Add RFC documents
Diffstat (limited to 'doc/rfc/rfc9497.txt')
-rw-r--r--doc/rfc/rfc9497.txt2915
1 files changed, 2915 insertions, 0 deletions
diff --git a/doc/rfc/rfc9497.txt b/doc/rfc/rfc9497.txt
new file mode 100644
index 0000000..4cdb7c3
--- /dev/null
+++ b/doc/rfc/rfc9497.txt
@@ -0,0 +1,2915 @@
+
+
+
+
+Internet Research Task Force (IRTF) A. Davidson
+Request for Comments: 9497 Brave Software
+Category: Informational A. Faz-Hernandez
+ISSN: 2070-1721 N. Sullivan
+ C. A. Wood
+ Cloudflare, Inc.
+ December 2023
+
+
+ Oblivious Pseudorandom Functions (OPRFs) Using Prime-Order Groups
+
+Abstract
+
+ An Oblivious Pseudorandom Function (OPRF) is a two-party protocol
+ between a client and a server for computing the output of a
+ Pseudorandom Function (PRF). The server provides the PRF private
+ 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 private 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.
+
+Status of This Memo
+
+ This document is not an Internet Standards Track specification; it is
+ published for informational purposes.
+
+ This document is a product of the Internet Research Task Force
+ (IRTF). The IRTF publishes the results of Internet-related research
+ and development activities. These results might not be suitable for
+ deployment. This RFC represents the consensus of the Crypto Forum
+ Research Group of the Internet Research Task Force (IRTF). Documents
+ approved for publication by the IRSG are not candidates for any level
+ of Internet Standard; see Section 2 of RFC 7841.
+
+ Information about the current status of this document, any errata,
+ and how to provide feedback on it may be obtained at
+ https://www.rfc-editor.org/info/rfc9497.
+
+Copyright Notice
+
+ Copyright (c) 2023 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (https://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document.
+
+Table of Contents
+
+ 1. Introduction
+ 1.1. Requirements Language
+ 1.2. Notation and Terminology
+ 2. Preliminaries
+ 2.1. Prime-Order Group
+ 2.2. Discrete Logarithm Equivalence Proofs
+ 2.2.1. Proof Generation
+ 2.2.2. Proof Verification
+ 3. Protocol
+ 3.1. Configuration
+ 3.2. Key Generation and Context Setup
+ 3.2.1. Deterministic Key Generation
+ 3.3. Online Protocol
+ 3.3.1. OPRF Protocol
+ 3.3.2. VOPRF Protocol
+ 3.3.3. POPRF Protocol
+ 4. Ciphersuites
+ 4.1. OPRF(ristretto255, SHA-512)
+ 4.2. OPRF(decaf448, SHAKE-256)
+ 4.3. OPRF(P-256, SHA-256)
+ 4.4. OPRF(P-384, SHA-384)
+ 4.5. OPRF(P-521, SHA-512)
+ 4.6. Future Ciphersuites
+ 4.7. Random Scalar Generation
+ 4.7.1. Rejection Sampling
+ 4.7.2. Random Number Generation Using Extra Random Bits
+ 5. Application Considerations
+ 5.1. Input Limits
+ 5.2. External Interface Recommendations
+ 5.3. Error Considerations
+ 5.4. POPRF Public Input
+ 6. IANA Considerations
+ 7. Security Considerations
+ 7.1. Security Properties
+ 7.2. Security Assumptions
+ 7.2.1. OPRF and VOPRF Assumptions
+ 7.2.2. POPRF Assumptions
+ 7.2.3. Static Diffie-Hellman Attack and Security Limits
+ 7.3. Domain Separation
+ 7.4. Timing Leaks
+ 8. References
+ 8.1. Normative References
+ 8.2. Informative References
+ Appendix A. Test Vectors
+ A.1. ristretto255-SHA512
+ A.1.1. OPRF Mode
+ A.1.2. VOPRF Mode
+ A.1.3. POPRF Mode
+ A.2. decaf448-SHAKE256
+ A.2.1. OPRF Mode
+ A.2.2. VOPRF Mode
+ A.2.3. POPRF Mode
+ A.3. P256-SHA256
+ A.3.1. OPRF Mode
+ A.3.2. VOPRF Mode
+ A.3.3. POPRF Mode
+ A.4. P384-SHA384
+ A.4.1. OPRF Mode
+ A.4.2. VOPRF Mode
+ A.4.3. POPRF Mode
+ A.5. P521-SHA512
+ A.5.1. OPRF Mode
+ A.5.2. VOPRF Mode
+ A.5.3. POPRF Mode
+ Acknowledgements
+ Authors' Addresses
+
+1. 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, wherein 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,
+ which the client knows. A Partially Oblivious PRF (POPRF) is a
+ variant of a VOPRF, where the 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 the 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 [JKKX16], privacy-preserving password stores
+ [SJKS17], and password-authenticated key exchange (PAKE) [OPAQUE].
+ Verifiable OPRFs are necessary in some applications, such as Privacy
+ Pass [PRIVACY-PASS]. Verifiable OPRFs have also been used for
+ password-protected secret sharing schemes, such as that of [JKK14].
+
+ 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.
+
+1.1. Requirements Language
+
+ 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 [RFC2119] [RFC8174] when, and only when, they appear in all
+ capitals, as shown here.
+
+1.2. 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(x, xLen) converts a nonnegative integer x into a byte array
+ of specified length xLen, as described in [RFC8017]. 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 to 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 the 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.
+
+ PRF: Pseudorandom Function
+
+ OPRF: Oblivious Pseudorandom Function
+
+ VOPRF: Verifiable Oblivious Pseudorandom Function
+
+ POPRF: Partially Oblivious Pseudorandom Function
+
+ Client: Protocol initiator. Learns PRF evaluation as the output of
+ the protocol.
+
+ Server: Computes the PRF using a private key. Learns nothing about
+ the client's input or output.
+
+2. Preliminaries
+
+ The protocols in this document have two primary dependencies:
+
+ Group: A prime-order group implementing the API described below in
+ Section 2.1. See Section 4 for specific instances of groups.
+
+ Hash: A cryptographic hash function whose output length is Nh bytes.
+
+ Section 4 specifies ciphersuites as combinations of Group and Hash.
+
+2.1. Prime-Order Group
+
+ In this document, we assume the construction of an additive, prime-
+ order group, denoted 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. (However, different representations of the group
+ for a single p may exist. Section 4 lists specific groups that
+ indicate both the 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 is
+ 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 Section 4. Security properties
+ of this function are described in [RFC9380].
+
+ HashToScalar(x): Deterministically maps an array of bytes x to an
+ element in GF(p). This function is optionally parameterized by a
+ DST; see Section 4. Security properties of this function are
+ described in [RFC9380], Section 10.5.
+
+ RandomScalar(): Chooses at random a nonzero element in GF(p).
+
+ ScalarInverse(s): Returns the inverse of input Scalar s on GF(p).
+
+ SerializeElement(A): Maps an Element A to a canonical byte array buf
+ of fixed-length Ne.
+
+ DeserializeElement(buf): Attempts to map a byte array buf to an
+ Element A 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 Section 4 for group-specific
+ input validation steps.
+
+ SerializeScalar(s): Maps Scalar s to a canonical byte array buf of
+ fixed-length Ns.
+
+ DeserializeScalar(buf): Attempts to map a byte array buf to Scalar
+ s. This function can raise a DeserializeError if deserialization
+ fails; see Section 4 for group-specific input validation steps.
+
+ Section 4 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 [RFC7748], which require accounting for cofactors,
+ Section 4 describes required steps necessary to ensure the resulting
+ group is of prime order.
+
+2.2. Discrete Logarithm Equivalence Proofs
+
+ A 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 [ChaumPedersen] proof,
+ which is shown to be zero-knowledge by Jarecki, et al. [JKK14] and is
+ noninteractive after applying the Fiat-Shamir transform [FS00].
+ Furthermore, Davidson, et al. [DGSTV18] 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 Pseudorandom Number Generator
+ (PRNG). The description is split into two subsections: 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.
+
+2.2.1. Proof Generation
+
+ Generating a proof is done with the GenerateProof function, as
+ defined below. Given Element values A and B, two non-empty lists of
+ Element values C and D of length m, and 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.
+
+ Input:
+
+ Scalar k
+ Element A
+ Element B
+ Element C[m]
+ Element D[m]
+
+ Output:
+
+ Proof proof
+
+ Parameters:
+
+ Group G
+
+ def GenerateProof(k, A, B, C, D):
+ (M, Z) = ComputeCompositesFast(k, B, C, D)
+
+ r = G.RandomScalar()
+ t2 = r * A
+ t3 = r * M
+
+ Bm = G.SerializeElement(B)
+ a0 = G.SerializeElement(M)
+ a1 = G.SerializeElement(Z)
+ a2 = G.SerializeElement(t2)
+ a3 = G.SerializeElement(t3)
+
+ challengeTranscript =
+ I2OSP(len(Bm), 2) || Bm ||
+ I2OSP(len(a0), 2) || a0 ||
+ I2OSP(len(a1), 2) || a1 ||
+ I2OSP(len(a2), 2) || a2 ||
+ I2OSP(len(a3), 2) || a3 ||
+ "Challenge"
+
+ c = G.HashToScalar(challengeTranscript)
+ s = r - c * k
+
+ return [c, s]
+
+ 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.
+
+ Input:
+
+ Scalar k
+ Element B
+ Element C[m]
+ Element D[m]
+
+ Output:
+
+ Element M
+ Element Z
+
+ Parameters:
+
+ Group G
+ PublicInput contextString
+
+ def ComputeCompositesFast(k, B, C, D):
+ Bm = G.SerializeElement(B)
+ seedDST = "Seed-" || contextString
+ seedTranscript =
+ I2OSP(len(Bm), 2) || Bm ||
+ I2OSP(len(seedDST), 2) || seedDST
+ seed = Hash(seedTranscript)
+
+ M = G.Identity()
+ for i in range(m):
+ Ci = G.SerializeElement(C[i])
+ Di = G.SerializeElement(D[i])
+ compositeTranscript =
+ I2OSP(len(seed), 2) || seed || I2OSP(i, 2) ||
+ I2OSP(len(Ci), 2) || Ci ||
+ I2OSP(len(Di), 2) || Di ||
+ "Composite"
+
+ di = G.HashToScalar(compositeTranscript)
+ M = di * C[i] + M
+
+ Z = k * M
+
+ return (M, Z)
+
+ When used in the protocol described in Section 3, the parameter
+ contextString is as defined in Section 3.2.
+
+2.2.2. Proof Verification
+
+ Verifying a proof is done with the VerifyProof function, as defined
+ below. This function takes Element values A and B, two non-empty
+ lists of Element values 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.
+
+ Input:
+
+ Element A
+ Element B
+ Element C[m]
+ Element D[m]
+ Proof proof
+
+ Output:
+
+ boolean verified
+
+ Parameters:
+
+ Group G
+
+ def VerifyProof(A, B, C, D, proof):
+ (M, Z) = ComputeComposites(B, C, D)
+ c = proof[0]
+ s = proof[1]
+
+ t2 = ((s * A) + (c * B))
+ t3 = ((s * M) + (c * Z))
+
+ Bm = G.SerializeElement(B)
+ a0 = G.SerializeElement(M)
+ a1 = G.SerializeElement(Z)
+ a2 = G.SerializeElement(t2)
+ a3 = G.SerializeElement(t3)
+
+ challengeTranscript =
+ I2OSP(len(Bm), 2) || Bm ||
+ I2OSP(len(a0), 2) || a0 ||
+ I2OSP(len(a1), 2) || a1 ||
+ I2OSP(len(a2), 2) || a2 ||
+ I2OSP(len(a3), 2) || a3 ||
+ "Challenge"
+
+ expectedC = G.HashToScalar(challengeTranscript)
+ verified = (expectedC == c)
+
+ return verified
+
+ The definition of ComputeComposites is given below.
+
+ Input:
+
+ Element B
+ Element C[m]
+ Element D[m]
+
+ Output:
+
+ Element M
+ Element Z
+
+ Parameters:
+
+ Group G
+ PublicInput contextString
+
+ def ComputeComposites(B, C, D):
+ Bm = G.SerializeElement(B)
+ seedDST = "Seed-" || contextString
+ seedTranscript =
+ I2OSP(len(Bm), 2) || Bm ||
+ I2OSP(len(seedDST), 2) || seedDST
+ seed = Hash(seedTranscript)
+
+ M = G.Identity()
+ Z = G.Identity()
+ for i in range(m):
+ Ci = G.SerializeElement(C[i])
+ Di = G.SerializeElement(D[i])
+ compositeTranscript =
+ I2OSP(len(seed), 2) || seed || I2OSP(i, 2) ||
+ I2OSP(len(Ci), 2) || Ci ||
+ I2OSP(len(Di), 2) || Di ||
+ "Composite"
+
+ di = G.HashToScalar(compositeTranscript)
+ M = di * C[i] + M
+ Z = di * D[i] + Z
+
+ return (M, Z)
+
+ When used in the protocol described in Section 3, the parameter
+ contextString is as defined in Section 3.2.
+
+3. Protocol
+
+ In this section, we define and describe three protocol variants
+ referred to as the OPRF, VOPRF, and POPRF modes. Each of these
+ variants involves two messages between the client and server, but
+ they differ slightly in terms of the security properties; see
+ Section 7.1 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 the output and the
+ server learns nothing. This interaction is shown below.
+
+ Client(input) Server(skS)
+ -------------------------------------------------------------------
+ blind, blindedElement = Blind(input)
+
+ blindedElement
+ ---------->
+
+ evaluatedElement = BlindEvaluate(skS, blindedElement)
+
+ evaluatedElement
+ <----------
+
+ output = Finalize(input, blind, evaluatedElement)
+
+ Figure 1: OPRF Protocol Overview
+
+ In the VOPRF mode, the client additionally receives proof that the
+ server used skS in computing the function. To achieve verifiability,
+ as in [JKK14], 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 is 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.
+
+ Client(input, pkS) <---- pkS ------ Server(skS, pkS)
+ -------------------------------------------------------------------
+ blind, blindedElement = Blind(input)
+
+ blindedElement
+ ---------->
+
+ evaluatedElement, proof = BlindEvaluate(skS, pkS,
+ blindedElement)
+
+ evaluatedElement, proof
+ <----------
+
+ output = Finalize(input, blind, evaluatedElement,
+ blindedElement, pkS, proof)
+
+ Figure 2: VOPRF Protocol Overview with Additional Proof
+
+ The POPRF mode extends the VOPRF mode such that the client and server
+ can additionally provide the public input info, which is used in
+ computing the PRF. That is, the client and server interact to
+ compute output = F(skS, input, info), as is shown below.
+
+ Client(input, pkS, info) <---- pkS ------ Server(skS, pkS, info)
+ -------------------------------------------------------------------
+ blind, blindedElement, tweakedKey = Blind(input, info, pkS)
+
+ blindedElement
+ ---------->
+
+ evaluatedElement, proof = BlindEvaluate(skS, blindedElement,
+ info)
+
+ evaluatedElement, proof
+ <----------
+
+ output = Finalize(input, blind, evaluatedElement,
+ blindedElement, proof, info, tweakedKey)
+
+ Figure 3: POPRF Protocol Overview with Additional Public Input
+
+ Each protocol consists of an offline setup phase and an online phase,
+ as described in Sections 3.2 and 3.3, respectively. Configuration
+ details for the offline phase are described in Section 3.1.
+
+3.1. Configuration
+
+ Each of the three protocol variants are identified with a one-byte
+ value (in hexadecimal):
+
+ +===========+=======+
+ | Mode | Value |
+ +===========+=======+
+ | modeOPRF | 0x00 |
+ +-----------+-------+
+ | modeVOPRF | 0x01 |
+ +-----------+-------+
+ | modePOPRF | 0x02 |
+ +-----------+-------+
+
+ Table 1: Identifiers
+ for Protocol Variants
+
+ 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 Section 4 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:
+
+ def CreateContextString(mode, identifier):
+ return "OPRFV1-" || I2OSP(mode, 1) || "-" || identifier
+
+3.2. Key Generation and Context Setup
+
+ In 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.
+
+ Input: None
+
+ Output:
+
+ Scalar skS
+ Element pkS
+
+ Parameters:
+
+ Group G
+
+ def GenerateKeyPair():
+ skS = G.RandomScalar()
+ pkS = G.ScalarMultGen(skS)
+ return skS, pkS
+
+ The second way to generate the key pair is via the deterministic key
+ generation function DeriveKeyPair, as described in Section 3.2.1.
+ 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:
+
+ def SetupOPRFServer(identifier, skS):
+ contextString = CreateContextString(modeOPRF, identifier)
+ return OPRFServerContext(contextString, skS)
+
+ def SetupOPRFClient(identifier):
+ contextString = CreateContextString(modeOPRF, identifier)
+ return OPRFClientContext(contextString)
+
+ The VOPRF variant server and client contexts are created as follows:
+
+ def SetupVOPRFServer(identifier, skS):
+ contextString = CreateContextString(modeVOPRF, identifier)
+ return VOPRFServerContext(contextString, skS)
+
+ def SetupVOPRFClient(identifier, pkS):
+ contextString = CreateContextString(modeVOPRF, identifier)
+ return VOPRFClientContext(contextString, pkS)
+
+ The POPRF variant server and client contexts are created as follows:
+
+ def SetupPOPRFServer(identifier, skS):
+ contextString = CreateContextString(modePOPRF, identifier)
+ return POPRFServerContext(contextString, skS)
+
+ def SetupPOPRFClient(identifier, pkS):
+ contextString = CreateContextString(modePOPRF, identifier)
+ return POPRFClientContext(contextString, pkS)
+
+3.2.1. Deterministic Key Generation
+
+ This section describes a deterministic key generation function,
+ DeriveKeyPair. It accepts a seed of 32 bytes generated from a
+ cryptographically secure random number generator and an optional
+ (possibly empty) info string. 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).
+
+ Input:
+
+ opaque seed[32]
+ PublicInput info
+
+ Output:
+
+ Scalar skS
+ Element pkS
+
+ Parameters:
+
+ Group G
+ PublicInput contextString
+
+ Errors: DeriveKeyPairError
+
+ def DeriveKeyPair(seed, info):
+ deriveInput = seed || I2OSP(len(info), 2) || info
+ counter = 0
+ skS = 0
+ while skS == 0:
+ if counter > 255:
+ raise DeriveKeyPairError
+ skS = G.HashToScalar(deriveInput || I2OSP(counter, 1),
+ DST = "DeriveKeyPair" || contextString)
+ counter = counter + 1
+ pkS = G.ScalarMultGen(skS)
+ return skS, pkS
+
+3.3. Online Protocol
+
+ In 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 Section 2.1
+
+ contextString: a PublicInput domain separation tag constructed
+ during context setup, as created in Section 3.1
+
+ skS and pkS: a Scalar and Element representing the private and
+ public keys configured for the client and server in Section 3.2
+
+ Applications serialize protocol messages between the client and
+ server for transmission. Element values and Scalar values are
+ serialized to byte arrays, and values of type Proof are serialized as
+ the concatenation of two serialized Scalar values. 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 Section 4 for more information and
+ requirements on input validation for each ciphersuite.
+
+3.3.1. OPRF Protocol
+
+ The 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 Section 5.3.
+
+ Input:
+
+ PrivateInput input
+
+ Output:
+
+ Scalar blind
+ Element blindedElement
+
+ Parameters:
+
+ Group G
+
+ Errors: InvalidInputError
+
+ def Blind(input):
+ blind = G.RandomScalar()
+ inputElement = G.HashToGroup(input)
+ if inputElement == G.Identity():
+ raise InvalidInputError
+ blindedElement = blind * inputElement
+
+ return blind, blindedElement
+
+ Clients store blind locally and send blindedElement to the server for
+ evaluation. Upon receipt, servers process blindedElement using the
+ BlindEvaluate function described below.
+
+ Input:
+
+ Scalar skS
+ Element blindedElement
+
+ Output:
+
+ Element evaluatedElement
+
+ def BlindEvaluate(skS, blindedElement):
+ evaluatedElement = skS * blindedElement
+ return evaluatedElement
+
+ 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.
+
+ Input:
+
+ PrivateInput input
+ Scalar blind
+ Element evaluatedElement
+
+ Output:
+
+ opaque output[Nh]
+
+ Parameters:
+
+ Group G
+
+ def Finalize(input, blind, evaluatedElement):
+ N = G.ScalarInverse(blind) * evaluatedElement
+ unblindedElement = G.SerializeElement(N)
+
+ hashInput = I2OSP(len(input), 2) || input ||
+ I2OSP(len(unblindedElement), 2) || unblindedElement ||
+ "Finalize"
+ return Hash(hashInput)
+
+ An entity that knows both the private key and the input can compute
+ the PRF result using the following Evaluate function.
+
+ Input:
+
+ Scalar skS
+ PrivateInput input
+
+ Output:
+
+ opaque output[Nh]
+
+ Parameters:
+
+ Group G
+
+ Errors: InvalidInputError
+
+ def Evaluate(skS, input):
+ inputElement = G.HashToGroup(input)
+ if inputElement == G.Identity():
+ raise InvalidInputError
+ evaluatedElement = skS * inputElement
+ issuedElement = G.SerializeElement(evaluatedElement)
+
+ hashInput = I2OSP(len(input), 2) || input ||
+ I2OSP(len(issuedElement), 2) || issuedElement ||
+ "Finalize"
+ return Hash(hashInput)
+
+3.3.2. VOPRF Protocol
+
+ The VOPRF protocol begins with the client blinding its input, using
+ the same Blind function as in Section 3.3.1. 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 a DLEQ proof using the following
+ BlindEvaluate function.
+
+ Input:
+
+ Scalar skS
+ Element pkS
+ Element blindedElement
+
+ Output:
+
+ Element evaluatedElement
+ Proof proof
+
+ Parameters:
+
+ Group G
+
+ def BlindEvaluate(skS, pkS, blindedElement):
+ evaluatedElement = skS * blindedElement
+ blindedElements = [blindedElement] // list of length 1
+ evaluatedElements = [evaluatedElement] // list of length 1
+ proof = GenerateProof(skS, G.Generator(), pkS,
+ blindedElements, evaluatedElements)
+ return evaluatedElement, proof
+
+ 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.
+
+ Input:
+
+ PrivateInput input
+ Scalar blind
+ Element evaluatedElement
+ Element blindedElement
+ Element pkS
+ Proof proof
+
+ Output:
+
+ opaque output[Nh]
+
+ Parameters:
+
+ Group G
+
+ Errors: VerifyError
+
+ def Finalize(input, blind, evaluatedElement,
+ blindedElement, pkS, proof):
+ blindedElements = [blindedElement] // list of length 1
+ evaluatedElements = [evaluatedElement] // list of length 1
+ if VerifyProof(G.Generator(), pkS, blindedElements,
+ evaluatedElements, proof) == false:
+ raise VerifyError
+
+ N = G.ScalarInverse(blind) * evaluatedElement
+ unblindedElement = G.SerializeElement(N)
+
+ hashInput = I2OSP(len(input), 2) || input ||
+ I2OSP(len(unblindedElement), 2) || unblindedElement ||
+ "Finalize"
+ return Hash(hashInput)
+
+ 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 that knows both the private key and the input can
+ compute the PRF result using the Evaluate function described in
+ Section 3.3.1.
+
+3.3.3. POPRF Protocol
+
+ The 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
+ Section 5.3.
+
+ Input:
+
+ PrivateInput input
+ PublicInput info
+ Element pkS
+
+ Output:
+
+ Scalar blind
+ Element blindedElement
+ Element tweakedKey
+
+ Parameters:
+
+ Group G
+
+ Errors: InvalidInputError
+
+ def Blind(input, info, pkS):
+ framedInfo = "Info" || I2OSP(len(info), 2) || info
+ m = G.HashToScalar(framedInfo)
+ T = G.ScalarMultGen(m)
+ tweakedKey = T + pkS
+ if tweakedKey == G.Identity():
+ raise InvalidInputError
+
+ blind = G.RandomScalar()
+ inputElement = G.HashToGroup(input)
+ if inputElement == G.Identity():
+ raise InvalidInputError
+
+ blindedElement = blind * inputElement
+
+ return blind, blindedElement, tweakedKey
+
+ 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 a DLEQ
+ proof using the following BlindEvaluate function.
+
+ Input:
+
+ Scalar skS
+ Element blindedElement
+ PublicInput info
+
+ Output:
+
+ Element evaluatedElement
+ Proof proof
+
+ Parameters:
+
+ Group G
+
+ Errors: InverseError
+
+ def BlindEvaluate(skS, blindedElement, info):
+ framedInfo = "Info" || I2OSP(len(info), 2) || info
+ m = G.HashToScalar(framedInfo)
+ t = skS + m
+ if t == 0:
+ raise InverseError
+
+ evaluatedElement = G.ScalarInverse(t) * blindedElement
+
+ tweakedKey = G.ScalarMultGen(t)
+ evaluatedElements = [evaluatedElement] // list of length 1
+ blindedElements = [blindedElement] // list of length 1
+ proof = GenerateProof(t, G.Generator(), tweakedKey,
+ evaluatedElements, blindedElements)
+
+ return evaluatedElement, proof
+
+ 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 private key of the server. Thus, clients
+ that cause this error should be assumed to know the server private
+ key. Hence, this error can be a signal for the server to replace its
+ private 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.
+
+ Input:
+
+ PrivateInput input
+ Scalar blind
+ Element evaluatedElement
+ Element blindedElement
+ Proof proof
+ PublicInput info
+ Element tweakedKey
+
+ Output:
+
+ opaque output[Nh]
+
+ Parameters:
+
+ Group G
+
+ Errors: VerifyError
+
+ def Finalize(input, blind, evaluatedElement, blindedElement,
+ proof, info, tweakedKey):
+ evaluatedElements = [evaluatedElement] // list of length 1
+ blindedElements = [blindedElement] // list of length 1
+ if VerifyProof(G.Generator(), tweakedKey, evaluatedElements,
+ blindedElements, proof) == false:
+ raise VerifyError
+
+ N = G.ScalarInverse(blind) * evaluatedElement
+ unblindedElement = G.SerializeElement(N)
+
+ hashInput = I2OSP(len(input), 2) || input ||
+ I2OSP(len(info), 2) || info ||
+ I2OSP(len(unblindedElement), 2) || unblindedElement ||
+ "Finalize"
+ return Hash(hashInput)
+
+ 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 that knows both the private key and the input can
+ compute the PRF result using the Evaluate function described below.
+
+ Input:
+
+ Scalar skS
+ PrivateInput input
+ PublicInput info
+
+ Output:
+
+ opaque output[Nh]
+
+ Parameters:
+
+ Group G
+
+ Errors: InvalidInputError, InverseError
+
+ def Evaluate(skS, input, info):
+ inputElement = G.HashToGroup(input)
+ if inputElement == G.Identity():
+ raise InvalidInputError
+
+ framedInfo = "Info" || I2OSP(len(info), 2) || info
+ m = G.HashToScalar(framedInfo)
+ t = skS + m
+ if t == 0:
+ raise InverseError
+ evaluatedElement = G.ScalarInverse(t) * inputElement
+ issuedElement = G.SerializeElement(evaluatedElement)
+
+ hashInput = I2OSP(len(input), 2) || input ||
+ I2OSP(len(info), 2) || info ||
+ I2OSP(len(issuedElement), 2) || issuedElement ||
+ "Finalize"
+ return Hash(hashInput)
+
+4. Ciphersuites
+
+ A 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 Section 2.1,
+ 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 [RFC9380], Section 3.1. For HashToScalar,
+ each group specifies an integer order that is used in reducing
+ integer values to a member of the corresponding scalar field.
+
+ Hash: A cryptographic hash function whose output length is Nh bytes
+ long.
+
+ This section 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 Section 4.6.
+
+ 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 Section 7.2 for
+ related discussion.
+
+4.1. OPRF(ristretto255, SHA-512)
+
+ This ciphersuite uses ristretto255 [RFC9496] for the Group and
+ SHA-512 for the hash function. The value of the ciphersuite
+ identifier is "ristretto255-SHA512".
+
+ Group: ristretto255 [RFC9496]
+
+ Order(): Return 2^252 + 27742317777372353535851937790883648493
+ (see [RFC9496]).
+
+ Identity(): As defined in [RFC9496].
+
+ Generator(): As defined in [RFC9496].
+
+ HashToGroup(): Use hash_to_ristretto255 [RFC9380] 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
+ an output length of 64 bytes, 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 Section 4.7
+ for implementation guidance.
+
+ SerializeElement(A): Implemented using the Encode function from
+ Section 4.3.2 of [RFC9496]; Ne = 32.
+
+ DeserializeElement(buf): Implemented using the Decode function
+ from Section 4.3.1 of [RFC9496]. 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.
+
+4.2. OPRF(decaf448, SHAKE-256)
+
+ This ciphersuite uses decaf448 [RFC9496] for the Group and SHAKE-256
+ for the hash function. The value of the ciphersuite identifier is
+ "decaf448-SHAKE256".
+
+ Group: decaf448 [RFC9496]
+
+ Order(): Return 2^446 - 13818066809895115352007386748515426880336
+ 692474882178609894547503885.
+
+ Identity(): As defined in [RFC9496].
+
+ Generator(): As defined in [RFC9496].
+
+ RandomScalar(): Implemented by returning a uniformly random
+ Scalar in the range [0, G.Order() - 1]. Refer to Section 4.7
+ for implementation guidance.
+
+ HashToGroup(): Use hash_to_decaf448 [RFC9380] 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 [RFC9496]; Ne = 56.
+
+ DeserializeElement(buf): Implemented using the Decode function
+ from Section 5.3.1 of [RFC9496]. 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.
+
+4.3. OPRF(P-256, SHA-256)
+
+ This ciphersuite uses P-256 [NISTCurves] for the Group and SHA-256
+ for the hash function. The value of the ciphersuite identifier is
+ "P256-SHA256".
+
+ Group: P-256 (secp256r1) [NISTCurves]
+
+ Order(): Return 0xffffffff00000000ffffffffffffffffbce6faada7179e8
+ 4f3b9cac2fc632551.
+
+ Identity(): As defined in [NISTCurves].
+
+ Generator(): As defined in [NISTCurves].
+
+ RandomScalar(): Implemented by returning a uniformly random
+ Scalar in the range [0, G.Order() - 1]. Refer to Section 4.7
+ for implementation guidance.
+
+ HashToGroup(): Use hash_to_curve with suite P256_XMD:SHA-
+ 256_SSWU_RO_ [RFC9380] and DST = "HashToGroup-" ||
+ contextString.
+
+ HashToScalar(): Use hash_to_field from [RFC9380] using L = 48,
+ expand_message_xmd with SHA-256, DST = "HashToScalar-" ||
+ contextString, and a 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 [SEC1]; 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 [SEC1]
+ and then performing partial public-key validation, as defined
+ in Section 5.6.2.3.4 of [KEYAGREEMENT]. 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 [SEC1]; Ns = 32.
+
+ DeserializeScalar(buf): Implemented by attempting to deserialize
+ a Scalar from a 32-byte string using Octet-String-to-Field-
+ Element from [SEC1]. This function can fail if the input does
+ not represent a Scalar in the range [0, G.Order() - 1].
+
+ Hash: SHA-256; Nh = 32.
+
+4.4. OPRF(P-384, SHA-384)
+
+ This ciphersuite uses P-384 [NISTCurves] for the Group and SHA-384
+ for the hash function. The value of the ciphersuite identifier is
+ "P384-SHA384".
+
+ Group: P-384 (secp384r1) [NISTCurves]
+
+ Order(): Return 0xfffffffffffffffffffffffffffffffffffffffffffffff
+ fc7634d81f4372ddf581a0db248b0a77aecec196accc52973.
+
+ Identity(): As defined in [NISTCurves].
+
+ Generator(): As defined in [NISTCurves].
+
+ RandomScalar(): Implemented by returning a uniformly random
+ Scalar in the range [0, G.Order() - 1]. Refer to Section 4.7
+ for implementation guidance.
+
+ HashToGroup(): Use hash_to_curve with suite P384_XMD:SHA-
+ 384_SSWU_RO_ [RFC9380] and DST = "HashToGroup-" ||
+ contextString.
+
+ HashToScalar(): Use hash_to_field from [RFC9380] using L = 72,
+ expand_message_xmd with SHA-384, DST = "HashToScalar-" ||
+ contextString, and a 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 [SEC1]; 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 [SEC1] and
+ then performing partial public-key validation, as defined in
+ Section 5.6.2.3.4 of [KEYAGREEMENT]. 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 [SEC1]; Ns = 48.
+
+ DeserializeScalar(buf): Implemented by attempting to deserialize
+ a Scalar from a 48-byte string using Octet-String-to-Field-
+ Element from [SEC1]. This function can fail if the input does
+ not represent a Scalar in the range [0, G.Order() - 1].
+
+ Hash: SHA-384; Nh = 48.
+
+4.5. OPRF(P-521, SHA-512)
+
+ This ciphersuite uses P-521 [NISTCurves] for the Group and SHA-512
+ for the hash function. The value of the ciphersuite identifier is
+ "P521-SHA512".
+
+ Group: P-521 (secp521r1) [NISTCurves]
+
+ Order(): Return 0x01fffffffffffffffffffffffffffffffffffffffffffff
+ ffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b889
+ 9c47aebb6fb71e91386409.
+
+ Identity(): As defined in [NISTCurves].
+
+ Generator(): As defined in [NISTCurves].
+
+ RandomScalar(): Implemented by returning a uniformly random
+ Scalar in the range [0, G.Order() - 1]. Refer to Section 4.7
+ for implementation guidance.
+
+ HashToGroup(): Use hash_to_curve with suite P521_XMD:SHA-
+ 512_SSWU_RO_ [RFC9380] and DST = "HashToGroup-" ||
+ contextString.
+
+ HashToScalar(): Use hash_to_field from [RFC9380] using L = 98,
+ expand_message_xmd with SHA-512, DST = "HashToScalar-" ||
+ contextString, and a 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 [SEC1]; Ne =
+ 67.
+
+ DeserializeElement(buf): Implemented by attempting to deserialize
+ a 67-byte input string to a public key using the compressed
+ Octet-String-to-Elliptic-Curve-Point method according to [SEC1]
+ and then performing partial public-key validation, as defined
+ in Section 5.6.2.3.4 of [KEYAGREEMENT]. 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 [SEC1]; Ns = 66.
+
+ DeserializeScalar(buf): Implemented by attempting to deserialize
+ a Scalar from a 66-byte string using Octet-String-to-Field-
+ Element from [SEC1]. This function can fail if the input does
+ not represent a Scalar in the range [0, G.Order() - 1].
+
+ Hash: SHA-512; Nh = 64.
+
+4.6. Future Ciphersuites
+
+ A critical requirement of implementing the prime-order group using
+ elliptic curves is a method to instantiate the function HashToGroup,
+ which 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 Section 4, we give
+ instantiations of this functionality based on the functions described
+ in [RFC9380]. Consequently, any OPRF implementation must adhere to
+ the implementation and security considerations discussed in [RFC9380]
+ 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 Section 2.1. 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 Section 7.2.3 for additional
+ details.
+
+4.7. Random Scalar Generation
+
+ Two popular algorithms for generating a random integer uniformly
+ distributed in the range [0, G.Order() - 1] are described in the
+ following subsections.
+
+4.7.1. Rejection Sampling
+
+ Generate 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.
+
+4.7.2. Random Number Generation Using Extra Random Bits
+
+ Generate 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 [RFC9380], Section 5 for the underlying derivation of L.
+
+5. Application Considerations
+
+ This section describes considerations for applications, including
+ external interface recommendations, explicit error treatment, and
+ public input representation for the POPRF protocol variant.
+
+5.1. Input Limits
+
+ Application 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.
+
+5.2. External Interface Recommendations
+
+ In Section 3.3, the interface of the protocol functions allows that
+ some inputs (and outputs) to be group Element and Scalar values.
+ However, implementations can instead operate over Element and Scalar
+ values internally and only expose interfaces that operate with an
+ application-specific format of messages.
+
+5.3. Error Considerations
+
+ Some 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 (Sections
+ 3.3.2 and 3.3.3).
+
+ DeserializeError: Group Element or Scalar deserialization failure
+ (Sections 2.1 and 3.3).
+
+ InputValidationError: Validation of byte array inputs failed
+ (Section 4).
+
+ 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 (Sections 3.3.1 and 3.3.3).
+
+ InverseError: A tweaked private key is invalid, i.e., has no
+ multiplicative inverse (Sections 2.1 and 3.3).
+
+ 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.
+
+5.4. POPRF Public Input
+
+ Functionally, 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 Section 7.2 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 [RFC9380], Section 10.4 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.
+
+6. IANA Considerations
+
+ This document has no IANA actions.
+
+7. Security Considerations
+
+ This 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.
+
+7.1. Security Properties
+
+ The 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 nonmalleable (i.e., we cannot compute a new evaluation
+ of F from an existing evaluation). A genuinely random function will
+ be nonmalleable with high probability, so a pseudorandom function
+ must be nonmalleable 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 [DGSTV18].
+
+ Beyond client input secrecy, 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 the client's private and public input. Both the 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 the 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.
+
+7.2. Security Assumptions
+
+ Below, we discuss the cryptographic security of each protocol variant
+ from Section 3, relative to the necessary cryptographic assumptions
+ that need to be made.
+
+7.2.1. OPRF and VOPRF Assumptions
+
+ The OPRF and VOPRF protocol variants in this document are based on
+ [JKK14]. In particular, the VOPRF construction is similar to the
+ [JKK14] construction with the following distinguishing properties:
+
+ 1. This document does not use session identifiers to differentiate
+ different instances of the protocol.
+
+ 2. 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
+ [DGSTV18].
+
+ The pseudorandomness and input secrecy (and verifiability) of the
+ OPRF (and VOPRF) protocols in [JKK14] are based on the One-More Gap
+ Computational Diffie-Hellman assumption that is computationally
+ difficult to solve in the corresponding prime-order group. In
+ [JKK14], 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.
+
+7.2.2. POPRF Assumptions
+
+ The POPRF construction in this document is based on the construction
+ known as 3HashSDHI, given by [TCRSTW21]. 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 [DGSTV18].
+
+ 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 [TCRSTW21] is computationally difficult to solve in the
+ corresponding prime-order group. Tyagi et al. [TCRSTW21] 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 [JKK14], which is a predecessor to
+ the POPRF variant in Section 3.3.3.)
+
+7.2.3. Static Diffie-Hellman Attack and Security Limits
+
+ A side effect of the OPRF protocol variants in this document is that
+ they allow instantiation of an oracle for constructing static Diffie-
+ Hellman (DH) samples; see [BG04] and [Cheon06]. 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).
+
+7.3. Domain Separation
+
+ Applications SHOULD construct input to the protocol to provide domain
+ separation. Any system that has multiple OPRF applications should
+ distinguish client inputs to ensure the OPRF results are separate.
+ Guidance for constructing info can be found in [RFC9380],
+ Section 3.1.
+
+7.4. Timing Leaks
+
+ To 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.
+
+8. References
+
+8.1. Normative References
+
+ [KEYAGREEMENT]
+ Barker, E., Chen, L., Roginsky, A., Vassilev, A., and R.
+ Davis, "Recommendation for pair-wise key-establishment
+ schemes using discrete logarithm cryptography", NIST
+ SP 800-56A (Rev. 3), DOI 10.6028/nist.sp.800-56ar3, April
+ 2018, <https://doi.org/10.6028/nist.sp.800-56ar3>.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119,
+ DOI 10.17487/RFC2119, March 1997,
+ <https://www.rfc-editor.org/info/rfc2119>.
+
+ [RFC8017] Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch,
+ "PKCS #1: RSA Cryptography Specifications Version 2.2",
+ RFC 8017, DOI 10.17487/RFC8017, November 2016,
+ <https://www.rfc-editor.org/info/rfc8017>.
+
+ [RFC8174] Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC
+ 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174,
+ May 2017, <https://www.rfc-editor.org/info/rfc8174>.
+
+ [RFC9380] Faz-Hernandez, A., Scott, S., Sullivan, N., Wahby, R. S.,
+ and C. A. Wood, "Hashing to Elliptic Curves", RFC 9380,
+ DOI 10.17487/RFC9380, August 2023,
+ <https://www.rfc-editor.org/info/rfc9380>.
+
+ [RFC9496] de Valence, H., Grigg, J., Hamburg, M., Lovecruft, I.,
+ Tankersley, G., and F. Valsorda, "The ristretto255 and
+ decaf448 Groups", RFC 9496, DOI 10.17487/RFC9496, December
+ 2023, <https://www.rfc-editor.org/info/rfc9496>.
+
+8.2. Informative References
+
+ [BG04] Brown, D. and R. Gallant, "The Static Diffie-Hellman
+ Problem", November 2004,
+ <https://eprint.iacr.org/2004/306>.
+
+ [ChaumPedersen]
+ Chaum, D. and T. Pedersen, "Wallet Databases with
+ Observers", Advances in Cryptology - CRYPTO' 92, pp.
+ 89-105, DOI 10.1007/3-540-48071-4_7, August 1992,
+ <https://doi.org/10.1007/3-540-48071-4_7>.
+
+ [Cheon06] Cheon, J., "Security Analysis of the Strong Diffie-Hellman
+ Problem", Advances in Cryptology - EUROCRYPT 2006, pp.
+ 1-11, DOI 10.1007/11761679_1, 2006,
+ <https://doi.org/10.1007/11761679_1>.
+
+ [DGSTV18] Davidson, A., Goldberg, I., Sullivan, N., Tankersley, G.,
+ and F. Valsorda, "Privacy Pass: Bypassing Internet
+ Challenges Anonymously", Proceedings on Privacy Enhancing
+ Technologies, vol. 2018, no. 3, pp. 164-180, DOI
+ 10.1515/popets-2018-0026, April 2018,
+ <https://doi.org/10.1515/popets-2018-0026>.
+
+ [FS00] Fiat, A. and A. Shamir, "How To Prove Yourself: Practical
+ Solutions to Identification and Signature Problems",
+ Advances in Cryptology - CRYPTO' 86, pp. 186-194,
+ DOI 10.1007/3-540-47721-7_12, 1986,
+ <https://doi.org/10.1007/3-540-47721-7_12>.
+
+ [JKK14] Jarecki, S., Kiayias, A., and H. Krawczyk, "Round-Optimal
+ Password-Protected Secret Sharing and T-PAKE in the
+ Password-Only Model", Lecture Notes in Computer Science,
+ pp. 233-253, DOI 10.1007/978-3-662-45608-8_13, 2014,
+ <https://doi.org/10.1007/978-3-662-45608-8_13>.
+
+ [JKKX16] Jarecki, S., Kiayias, A., Krawczyk, H., and J. Xu,
+ "Highly-Efficient and Composable Password-Protected Secret
+ Sharing (Or: How to Protect Your Bitcoin Wallet Online)",
+ 2016 IEEE European Symposium on Security and Privacy
+ (EuroS&P), DOI 10.1109/eurosp.2016.30, March 2016,
+ <https://doi.org/10.1109/eurosp.2016.30>.
+
+ [NISTCurves]
+ National Institute of Standards and Technology (NIST),
+ "Digital Signature Standard (DSS)", FIPS PUB 186-5,
+ DOI 10.6028/NIST.FIPS.186-5, February 2023,
+ <https://doi.org/10.6028/NIST.FIPS.186-5>.
+
+ [OPAQUE] Bourdrez, D., Krawczyk, H., Lewi, K., and C. A. Wood, "The
+ OPAQUE Asymmetric PAKE Protocol", Work in Progress,
+ Internet-Draft, draft-irtf-cfrg-opaque-13, 18 December
+ 2023, <https://datatracker.ietf.org/doc/html/draft-irtf-
+ cfrg-opaque-13>.
+
+ [PRIVACY-PASS]
+ Celi, S., Davidson, A., Valdez, S., and C. A. Wood,
+ "Privacy Pass Issuance Protocol", Work in Progress,
+ Internet-Draft, draft-ietf-privacypass-protocol-16, 3
+ October 2023, <https://datatracker.ietf.org/doc/html/
+ draft-ietf-privacypass-protocol-16>.
+
+ [PrivacyPass]
+ "Privacy Pass", commit 085380a, March 2018,
+ <https://github.com/privacypass/team>.
+
+ [RFC7748] Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves
+ for Security", RFC 7748, DOI 10.17487/RFC7748, January
+ 2016, <https://www.rfc-editor.org/info/rfc7748>.
+
+ [SEC1] Standards for Efficient Cryptography Group (SECG), "SEC 1:
+ Elliptic Curve Cryptography", May 2009,
+ <https://www.secg.org/sec1-v2.pdf>.
+
+ [SJKS17] Shirvanian, M., Jarecki, S., Krawczyk, H., and N. Saxena,
+ "SPHINX: A Password Store that Perfectly Hides Passwords
+ from Itself", 2017 IEEE 37th International Conference on
+ Distributed Computing Systems (ICDCS),
+ DOI 10.1109/ICDCS.2017.64, June 2017,
+ <https://doi.org/10.1109/ICDCS.2017.64>.
+
+ [TCRSTW21] Tyagi, N., Celi, S., Ristenpart, T., Sullivan, N.,
+ Tessaro, S., and C. A. Wood, "A Fast and Simple Partially
+ Oblivious PRF, with Applications", Advances in Cryptology
+ - EUROCRYPT 2022 pp. 674-705,
+ DOI 10.1007/978-3-031-07085-3_23, May 2022,
+ <https://doi.org/10.1007/978-3-031-07085-3_23>.
+
+Appendix A. Test Vectors
+
+ This section includes test vectors for the protocol variants
+ specified in this document. For each ciphersuite specified in
+ Section 4, there is a set of test vectors for the protocol when
+ running 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 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 Nh bytes
+ long.
+
+ 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, denoted Seed, and info string, denoted KeyInfo,
+ which are listed as well, using the DeriveKeyPair function from
+ Section 3.2.
+
+A.1. ristretto255-SHA512
+
+A.1.1. OPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063
+ b0e
+
+A.1.1.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = 609a0ae68c15a3cf6903766461307e5c8bb2f95e7e6550e1ffa
+ 2dc99e412803c
+ EvaluationElement = 7ec6578ae5120958eb2db1745758ff379e77cb64fe77b0b2
+ d8cc917ea0869c7e
+ Output = 527759c3d9366f277d8c6020418d96bb393ba2afb20ff90df23fb770826
+ 4e2f3ab9135e3bd69955851de4b1f9fe8a0973396719b7912ba9ee8aa7d0b5e24bcf
+ 6
+
+A.1.1.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = da27ef466870f5f15296299850aa088629945a17d1f5b7f5ff0
+ 43f76b3c06418
+ EvaluationElement = b4cbf5a4f1eeda5a63ce7b77c7d23f461db3fcab0dd28e4e
+ 17cecb5c90d02c25
+ Output = f4a74c9c592497375e796aa837e907b1a045d34306a749db9f34221f7e7
+ 50cb4f2a6413a6bf6fa5e19ba6348eb673934a722a7ede2e7621306d18951e7cf2c7
+ 3
+
+A.1.2. VOPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = e6f73f344b79b379f1a0dd37e07ff62e38d9f71345ce62ae3a9bc60b04ccd
+ 909
+ pkSm = c803e2cc6b05fc15064549b5920659ca4a77b2cca6f04f6b357009335476a
+ d4e
+
+A.1.2.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = 863f330cc1a1259ed5a5998a23acfd37fb4351a793a5b3c090b
+ 642ddc439b945
+ EvaluationElement = aa8fa048764d5623868679402ff6108d2521884fa138cd7f
+ 9c7669a9a014267e
+ Proof = ddef93772692e535d1a53903db24367355cc2cc78de93b3be5a8ffcc6985
+ dd066d4346421d17bf5117a2a1ff0fcb2a759f58a539dfbe857a40bce4cf49ec600d
+ ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98
+ 81aa6f61d645fc0e
+ Output = b58cfbe118e0cb94d79b5fd6a6dafb98764dff49c14e1770b566e42402d
+ a1a7da4d8527693914139caee5bd03903af43a491351d23b430948dd50cde10d32b3
+ c
+
+A.1.2.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = cc0b2a350101881d8a4cba4c80241d74fb7dcbfde4a61fde2f9
+ 1443c2bf9ef0c
+ EvaluationElement = 60a59a57208d48aca71e9e850d22674b611f752bed48b36f
+ 7a91b372bd7ad468
+ Proof = 401a0da6264f8cf45bb2f5264bc31e109155600babb3cd4e5af7d181a2c9
+ dc0a67154fabf031fd936051dec80b0b6ae29c9503493dde7393b722eafdf5a50b02
+ ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98
+ 81aa6f61d645fc0e
+ Output = 8a9a2f3c7f085b65933594309041fc1898d42d0858e59f90814ae90571a
+ 6df60356f4610bf816f27afdd84f47719e480906d27ecd994985890e5f539e7ea74b
+ 6
+
+A.1.2.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706,222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d9881aa6f61d645fc0
+ e
+ BlindedElement = 863f330cc1a1259ed5a5998a23acfd37fb4351a793a5b3c090b
+ 642ddc439b945,90a0145ea9da29254c3a56be4fe185465ebb3bf2a1801f7124bbba
+ dac751e654
+ EvaluationElement = aa8fa048764d5623868679402ff6108d2521884fa138cd7f
+ 9c7669a9a014267e,cc5ac221950a49ceaa73c8db41b82c20372a4c8d63e5dded2db
+ 920b7eee36a2a
+ Proof = cc203910175d786927eeb44ea847328047892ddf8590e723c37205cb7460
+ 0b0a5ab5337c8eb4ceae0494c2cf89529dcf94572ed267473d567aeed6ab873dee08
+ ProofRandomScalar = 419c4f4f5052c53c45f3da494d2b67b220d02118e0857cdb
+ cf037f9ea84bbe0c
+ Output = b58cfbe118e0cb94d79b5fd6a6dafb98764dff49c14e1770b566e42402d
+ a1a7da4d8527693914139caee5bd03903af43a491351d23b430948dd50cde10d32b3
+ c,8a9a2f3c7f085b65933594309041fc1898d42d0858e59f90814ae90571a6df6035
+ 6f4610bf816f27afdd84f47719e480906d27ecd994985890e5f539e7ea74b6
+
+A.1.3. POPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 145c79c108538421ac164ecbe131942136d5570b16d8bf41a24d4337da981
+ e07
+ pkSm = c647bef38497bc6ec077c22af65b696efa43bff3b4a1975a3e8e0a1c5a79d
+ 631
+
+A.1.3.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = c8713aa89241d6989ac142f22dba30596db635c772cbf25021f
+ dd8f3d461f715
+ EvaluationElement = 1a4b860d808ff19624731e67b5eff20ceb2df3c3c03b906f
+ 5693e2078450d874
+ Proof = 41ad1a291aa02c80b0915fbfbb0c0afa15a57e2970067a602ddb9e8fd6b7
+ 100de32e1ecff943a36f0b10e3dae6bd266cdeb8adf825d86ef27dbc6c0e30c52206
+ ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98
+ 81aa6f61d645fc0e
+ Output = ca688351e88afb1d841fde4401c79efebb2eb75e7998fa9737bd5a82a15
+ 2406d38bd29f680504e54fd4587eddcf2f37a2617ac2fbd2993f7bdf45442ace7d22
+ 1
+
+A.1.3.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706
+ BlindedElement = f0f0b209dd4d5f1844dac679acc7761b91a2e704879656cb7c2
+ 01e82a99ab07d
+ EvaluationElement = 8c3c9d064c334c6991e99f286ea2301d1bde170b54003fb9
+ c44c6d7bd6fc1540
+ Proof = 4c39992d55ffba38232cdac88fe583af8a85441fefd7d1d4a8d0394cd1de
+ 77018bf135c174f20281b3341ab1f453fe72b0293a7398703384bed822bfdeec8908
+ ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98
+ 81aa6f61d645fc0e
+ Output = 7c6557b276a137922a0bcfc2aa2b35dd78322bd500235eb6d6b6f91bc5b
+ 56a52de2d65612d503236b321f5d0bebcbc52b64b92e426f29c9b8b69f52de98ae50
+ 7
+
+A.1.3.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f
+ 6706,222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d9881aa6f61d645fc0
+ e
+ BlindedElement = c8713aa89241d6989ac142f22dba30596db635c772cbf25021f
+ dd8f3d461f715,423a01c072e06eb1cce96d23acce06e1ea64a609d7ec9e9023f304
+ 9f2d64e50c
+ EvaluationElement = 1a4b860d808ff19624731e67b5eff20ceb2df3c3c03b906f
+ 5693e2078450d874,aa1f16e903841036e38075da8a46655c94fc92341887eb5819f
+ 46312adfc0504
+ Proof = 43fdb53be399cbd3561186ae480320caa2b9f36cca0e5b160c4a677b8bbf
+ 4301b28f12c36aa8e11e5a7ef551da0781e863a6dc8c0b2bf5a149c9e00621f02006
+ ProofRandomScalar = 419c4f4f5052c53c45f3da494d2b67b220d02118e0857cdb
+ cf037f9ea84bbe0c
+ Output = ca688351e88afb1d841fde4401c79efebb2eb75e7998fa9737bd5a82a15
+ 2406d38bd29f680504e54fd4587eddcf2f37a2617ac2fbd2993f7bdf45442ace7d22
+ 1,7c6557b276a137922a0bcfc2aa2b35dd78322bd500235eb6d6b6f91bc5b56a52de
+ 2d65612d503236b321f5d0bebcbc52b64b92e426f29c9b8b69f52de98ae507
+
+A.2. decaf448-SHAKE256
+
+A.2.1. OPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = e8b1375371fd11ebeb224f832dcc16d371b4188951c438f751425699ed29e
+ cc80c6c13e558ccd67634fd82eac94aa8d1f0d7fee990695d1e
+
+A.2.1.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = e0ae01c4095f08e03b19baf47ffdc19cb7d98e583160522a3c7
+ d6a0b2111cd93a126a46b7b41b730cd7fc943d4e28e590ed33ae475885f6c
+ EvaluationElement = 50ce4e60eed006e22e7027454b5a4b8319eb2bc8ced609eb
+ 19eb3ad42fb19e06ba12d382cbe7ae342a0cad6ead0ef8f91f00bb7f0cd9c0a2
+ Output = 37d3f7922d9388a15b561de5829bbf654c4089ede89c0ce0f3f85bcdba0
+ 9e382ce0ab3507e021f9e79706a1798ffeac68ebd5cf62e5eb9838c7068351d97ae3
+ 7
+
+A.2.1.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = 86a88dc5c6331ecfcb1d9aacb50a68213803c462e377577cacc
+ 00af28e15f0ddbc2e3d716f2f39ef95f3ec1314a2c64d940a9f295d8f13bb
+ EvaluationElement = 162e9fa6e9d527c3cd734a31bf122a34dbd5bcb7bb23651f
+ 1768a7a9274cc116c03b58afa6f0dede3994a60066c76370e7328e7062fd5819
+ Output = a2a652290055cb0f6f8637a249ee45e32ef4667db0b4c80c0a70d2a6416
+ 4d01525cfdad5d870a694ec77972b9b6ec5d2596a5223e5336913f945101f0137f55
+ e
+
+A.2.2. VOPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = e3c01519a076a326a0eb566343e9b21c115fa18e6e85577ddbe890b33104f
+ cc2835ddfb14a928dc3f5d79b936e17c76b99e0bf6a1680930e
+ pkSm = 945fc518c47695cf65217ace04b86ac5e4cbe26ca649d52854bb16c494ce0
+ 9069d6add96b20d4b0ae311a87c9a73e3a146b525763ab2f955
+
+A.2.2.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = 7261bbc335c664ba788f1b1a1a4cd5190cc30e787ef277665ac
+ 1d314f8861e3ec11854ce3ddd42035d9e0f5cddde324c332d8c880abc00eb
+ EvaluationElement = ca1491a526c28d880806cf0fb0122222392cf495657be6e4
+ c9d203bceffa46c86406caf8217859d3fb259077af68e5d41b3699410781f467
+ Proof = f84bbeee47aedf43558dae4b95b3853635a9fc1a9ea7eac9b454c64c66c4
+ f49cd1c72711c7ac2e06c681e16ea693d5500bbd7b56455df52f69e00b76b4126961
+ e1562fdbaaac40b7701065cbeece3febbfe09e00160f81775d36daed99d8a2a10be0
+ 759e01b7ee81217203416c9db208
+ ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
+ 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
+ Output = e2ac40b634f36cccd8262b285adff7c9dcc19cd308564a5f4e581d1a853
+ 5773b86fa4fc9f2203c370763695c5093aea4a7aedec4488b1340ba3bf663a23098c
+ 1
+
+A.2.2.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = 88287e553939090b888ddc15913e1807dc4757215555e1c3a79
+ 488ef311594729c7fa74c772a732b78440b7d66d0aa35f3bb316f1d93e1b2
+ EvaluationElement = c00978c73e8e4ee1d447ab0d3ad1754055e72cc85c08e3a0
+ db170909a9c61cbff1f1e7015f289e3038b0f341faea5d7780c130106065c231
+ Proof = 7a2831a6b237e11ac1657d440df93bc5ce00f552e6020a99d5c956ffc4d0
+ 7b5ade3e82ecdc257fd53d76239e733e0a1313e84ce16cc0d82734806092a693d7e8
+ d3c420c2cb6ccd5d0ca32514fb78e9ad0973ebdcb52eba438fc73948d76339ee7101
+ 21d83e2fe6f001cfdf551aff9f36
+ ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
+ 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
+ Output = 862952380e07ec840d9f6e6f909c5a25d16c3dacb586d89a181b4aa7380
+ c959baa8c480fe8e6c64e089d68ea7aeeb5817bd524d7577905b5bab487690048c94
+ 1
+
+A.2.2.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112,b1b748135d405ce
+ 48c6973401d9455bb8ccd18b01d0295c0627f67661200dbf9569f73fbb3925daa043
+ a070e5f953d80bb464ea369e5522b
+ BlindedElement = 7261bbc335c664ba788f1b1a1a4cd5190cc30e787ef277665ac
+ 1d314f8861e3ec11854ce3ddd42035d9e0f5cddde324c332d8c880abc00eb,2e15f3
+ 93c035492a1573627a3606e528c6294c767c8d43b8c691ef70a52cc7dc7d1b53fe45
+ 8350a270abb7c231b87ba58266f89164f714d9
+ EvaluationElement = ca1491a526c28d880806cf0fb0122222392cf495657be6e4
+ c9d203bceffa46c86406caf8217859d3fb259077af68e5d41b3699410781f467,8ec
+ 68e9871b296e81c55647ce64a04fe75d19932f1400544cd601468c60f998408bbb54
+ 6601d4a636e8be279e558d70b95c8d4a4f61892be
+ Proof = 167d922f0a6ffa845eed07f8aa97b6ac746d902ecbeb18f49c009adc0521
+ eab1e4d275b74a2dc266b7a194c854e85e7eb54a9a36376dfc04ec7f3bd55fc9618c
+ 3970cb548e064f8a2f06183a5702933dbc3e4c25a73438f2108ee1981c306181003c
+ 7ea92fce963ec7b4ba4f270e6d38
+ ProofRandomScalar = 63798726803c9451ba405f00ef3acb633ddf0c420574a2ec
+ 6cbf28f840800e355c9fbaac10699686de2724ed22e797a00f3bd93d105a7f23
+ Output = e2ac40b634f36cccd8262b285adff7c9dcc19cd308564a5f4e581d1a853
+ 5773b86fa4fc9f2203c370763695c5093aea4a7aedec4488b1340ba3bf663a23098c
+ 1,862952380e07ec840d9f6e6f909c5a25d16c3dacb586d89a181b4aa7380c959baa
+ 8c480fe8e6c64e089d68ea7aeeb5817bd524d7577905b5bab487690048c941
+
+A.2.3. POPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 792a10dcbd3ba4a52a054f6f39186623208695301e7adb9634b74709ab22d
+ e402990eb143fd7c67ac66be75e0609705ecea800992aac8e19
+ pkSm = 6c9d12723a5bbcf305522cc04b4a34d9ced2e12831826018ea7b5dcf54526
+ 47ad262113059bf0f6e4354319951b9d513c74f29cb0eec38c1
+
+A.2.3.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = 161183c13c6cb33b0e4f9b7365f8c5c12d13c72f8b62d276ca0
+ 9368d093dce9b42198276b9e9d870ac392dda53efd28d1b7e6e8c060cdc42
+ EvaluationElement = 06ec89dfde25bb2a6f0145ac84b91ac277b35de39ad1d6f4
+ 02a8e46414952ce0d9ea1311a4ece283e2b01558c7078b040cfaa40dd63b3e6c
+ Proof = 66caee75bf2460429f620f6ad3e811d524cb8ddd848a435fc5d89af48877
+ abf6506ee341a0b6f67c2d76cd021e5f3d1c9abe5aa9f0dce016da746135fedba2af
+ 41ed1d01659bfd6180d96bc1b7f320c0cb6926011ce392ecca748662564892bae665
+ 16acaac6ca39aadf6fcca95af406
+ ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
+ 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
+ Output = 4423f6dcc1740688ea201de57d76824d59cd6b859e1f9884b7eebc49b0b
+ 971358cf9cb075df1536a8ea31bcf55c3e31c2ba9cfa8efe54448d17091daeb9924e
+ d
+
+A.2.3.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112
+ BlindedElement = 12082b6a381c6c51e85d00f2a3d828cdeab3f5cb19a10b9c014
+ c33826764ab7e7cfb8b4ff6f411bddb2d64e62a472af1cd816e5b712790c6
+ EvaluationElement = f2919b7eedc05ab807c221fce2b12c4ae9e19e6909c47845
+ 64b690d1972d2994ca623f273afc67444d84ea40cbc58fcdab7945f321a52848
+ Proof = a295677c54d1bc4286330907fc2490a7de163da26f9ce03a462a452fea42
+ 2b19ade296ba031359b3b6841e48455d20519ad01b4ac4f0b92e76d3cf16fbef0a3f
+ 72791a8401ef2d7081d361e502e96b2c60608b9fa566f43d4611c2f161d83aabef7f
+ 8017332b26ed1daaf80440772022
+ ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
+ 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
+ Output = 8691905500510843902c44bdd9730ab9dc3925aa58ff9dd42765a2baf63
+ 3126de0c3adb93bef5652f38e5827b6396e87643960163a560fc4ac9738c8de4e4a8
+ d
+
+A.2.3.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
+ 3833a26e9388336361686ff1f83df55046504dfecad8549ba112,b1b748135d405ce
+ 48c6973401d9455bb8ccd18b01d0295c0627f67661200dbf9569f73fbb3925daa043
+ a070e5f953d80bb464ea369e5522b
+ BlindedElement = 161183c13c6cb33b0e4f9b7365f8c5c12d13c72f8b62d276ca0
+ 9368d093dce9b42198276b9e9d870ac392dda53efd28d1b7e6e8c060cdc42,fc8847
+ d43fb4cea4e408f585661a8f2867533fa91d22155d3127a22f18d3b007add480f7d3
+ 00bca93fa47fe87ae06a57b7d0f0d4c30b12f0
+ EvaluationElement = 06ec89dfde25bb2a6f0145ac84b91ac277b35de39ad1d6f4
+ 02a8e46414952ce0d9ea1311a4ece283e2b01558c7078b040cfaa40dd63b3e6c,2e7
+ 4c626d07de49b1c8c21d87120fd78105f485e36816af9bde3e3efbeef76815326062
+ fd333925b66c5ce5a20f100bf01770c16609f990a
+ Proof = fd94db736f97ea4efe9d0d4ad2933072697a6bbeb32834057b23edf7c700
+ 9f011dfa72157f05d2a507c2bbf0b54cad99ab99de05921c021fda7d70e65bcecdb0
+ 5f9a30154127ace983c74d10fd910b554c5e95f6bd1565fd1f3dbbe3c523ece5c72d
+ 57a559b7be1368c4786db4a3c910
+ ProofRandomScalar = 63798726803c9451ba405f00ef3acb633ddf0c420574a2ec
+ 6cbf28f840800e355c9fbaac10699686de2724ed22e797a00f3bd93d105a7f23
+ Output = 4423f6dcc1740688ea201de57d76824d59cd6b859e1f9884b7eebc49b0b
+ 971358cf9cb075df1536a8ea31bcf55c3e31c2ba9cfa8efe54448d17091daeb9924e
+ d,8691905500510843902c44bdd9730ab9dc3925aa58ff9dd42765a2baf633126de0
+ c3adb93bef5652f38e5827b6396e87643960163a560fc4ac9738c8de4e4a8d
+
+A.3. P256-SHA256
+
+A.3.1. OPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 159749d750713afe245d2d39ccfaae8381c53ce92d098a9375ee70739c7ac
+ 0bf
+
+A.3.1.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 03723a1e5c09b8b9c18d1dcbca29e8007e95f14f4732d9346d4
+ 90ffc195110368d
+ EvaluationElement = 030de02ffec47a1fd53efcdd1c6faf5bdc270912b8749e78
+ 3c7ca75bb412958832
+ Output = a0b34de5fa4c5b6da07e72af73cc507cceeb48981b97b7285fc375345fe
+ 495dd
+
+A.3.1.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 03cc1df781f1c2240a64d1c297b3f3d16262ef5d4cf10273488
+ 2675c26231b0838
+ EvaluationElement = 03a0395fe3828f2476ffcd1f4fe540e5a8489322d398be3c
+ 4e5a869db7fcb7c52c
+ Output = c748ca6dd327f0ce85f4ae3a8cd6d4d5390bbb804c9e12dcf94f853fece
+ 3dcce
+
+A.3.2. VOPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = ca5d94c8807817669a51b196c34c1b7f8442fde4334a7121ae4736364312f
+ ca6
+ pkSm = 03e17e70604bcabe198882c0a1f27a92441e774224ed9c702e51dd17038b1
+ 02462
+
+A.3.2.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 02dd05901038bb31a6fae01828fd8d0e49e35a486b5c5d4b499
+ 4013648c01277da
+ EvaluationElement = 0209f33cab60cf8fe69239b0afbcfcd261af4c1c5632624f
+ 2e9ba29b90ae83e4a2
+ Proof = e7c2b3c5c954c035949f1f74e6bce2ed539a3be267d1481e9ddb178533df
+ 4c2664f69d065c604a4fd953e100b856ad83804eb3845189babfa5a702090d6fc5fa
+ ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 0412e8f78b02c415ab3a288e228978376f99927767ff37c5718d420010a
+ 645a1
+
+A.3.2.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 03cd0f033e791c4d79dfa9c6ed750f2ac009ec46cd4195ca6fd
+ 3800d1e9b887dbd
+ EvaluationElement = 030d2985865c693bf7af47ba4d3a3813176576383d19aff0
+ 03ef7b0784a0d83cf1
+ Proof = 2787d729c57e3d9512d3aa9e8708ad226bc48e0f1750b0767aaff73482c4
+ 4b8d2873d74ec88aebd3504961acea16790a05c542d9fbff4fe269a77510db00abab
+ ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 771e10dcd6bcd3664e23b8f2a710cfaaa8357747c4a8cbba03133967b5c
+ 24f18
+
+A.3.2.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364,f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b
+ 1
+ BlindedElement = 02dd05901038bb31a6fae01828fd8d0e49e35a486b5c5d4b499
+ 4013648c01277da,03462e9ae64cae5b83ba98a6b360d942266389ac369b923eb3d5
+ 57213b1922f8ab
+ EvaluationElement = 0209f33cab60cf8fe69239b0afbcfcd261af4c1c5632624f
+ 2e9ba29b90ae83e4a2,02bb24f4d838414aef052a8f044a6771230ca69c0a5677540
+ fff738dd31bb69771
+ Proof = bdcc351707d02a72ce49511c7db990566d29d6153ad6f8982fad2b435d6c
+ e4d60da1e6b3fa740811bde34dd4fe0aa1b5fe6600d0440c9ddee95ea7fad7a60cf2
+ ProofRandomScalar = 350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
+ 51943c8026877963
+ Output = 0412e8f78b02c415ab3a288e228978376f99927767ff37c5718d420010a
+ 645a1,771e10dcd6bcd3664e23b8f2a710cfaaa8357747c4a8cbba03133967b5c24f
+ 18
+
+A.3.3. POPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 6ad2173efa689ef2c27772566ad7ff6e2d59b3b196f00219451fb2c89ee4d
+ ae2
+ pkSm = 030d7ff077fddeec965db14b794f0cc1ba9019b04a2f4fcc1fa525dedf72e
+ 2a3e3
+
+A.3.3.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Info = 7465737420696e666f
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 031563e127099a8f61ed51eeede05d747a8da2be329b40ba1f0
+ db0b2bd9dd4e2c0
+ EvaluationElement = 02c5e5300c2d9e6ba7f3f4ad60500ad93a0157e6288eb04b
+ 67e125db024a2c74d2
+ Proof = f8a33690b87736c854eadfcaab58a59b8d9c03b569110b6f31f8bf7577f3
+ fbb85a8a0c38468ccde1ba942be501654adb106167c8eb178703ccb42bccffb9231a
+ ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 193a92520bd8fd1f37accb918040a57108daa110dc4f659abe212636d24
+ 5c592
+
+A.3.3.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 021a440ace8ca667f261c10ac7686adc66a12be31e3520fca31
+ 7643a1eee9dcd4d
+ EvaluationElement = 0208ca109cbae44f4774fc0bdd2783efdcb868cb4523d521
+ 96f700210e777c5de3
+ Proof = 043a8fb7fc7fd31e35770cabda4753c5bf0ecc1e88c68d7d35a62bf2631e
+ 875af4613641be2d1875c31d1319d191c4bbc0d04875f4fd03c31d3d17dd8e069b69
+ ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 1e6d164cfd835d88a31401623549bf6b9b306628ef03a7962921d62bc5f
+ fce8c
+
+A.3.3.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364,f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b
+ 1
+ BlindedElement = 031563e127099a8f61ed51eeede05d747a8da2be329b40ba1f0
+ db0b2bd9dd4e2c0,03ca4ff41c12fadd7a0bc92cf856732b21df652e01a3abdf0fa8
+ 847da053db213c
+ EvaluationElement = 02c5e5300c2d9e6ba7f3f4ad60500ad93a0157e6288eb04b
+ 67e125db024a2c74d2,02f0b6bcd467343a8d8555a99dc2eed0215c71898c5edb77a
+ 3d97ddd0dbad478e8
+ Proof = 8fbd85a32c13aba79db4b42e762c00687d6dbf9c8cb97b2a225645ccb00d
+ 9d7580b383c885cdfd07df448d55e06f50f6173405eee5506c0ed0851ff718d13e68
+ ProofRandomScalar = 350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
+ 51943c8026877963
+ Output = 193a92520bd8fd1f37accb918040a57108daa110dc4f659abe212636d24
+ 5c592,1e6d164cfd835d88a31401623549bf6b9b306628ef03a7962921d62bc5ffce
+ 8c
+
+A.4. P384-SHA384
+
+A.4.1. OPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = dfe7ddc41a4646901184f2b432616c8ba6d452f9bcd0c4f75a5150ef2b2ed
+ 02ef40b8b92f60ae591bcabd72a6518f188
+
+A.4.1.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 02a36bc90e6db34096346eaf8b7bc40ee1113582155ad379700
+ 3ce614c835a874343701d3f2debbd80d97cbe45de6e5f1f
+ EvaluationElement = 03af2a4fc94770d7a7bf3187ca9cc4faf3732049eded2442
+ ee50fbddda58b70ae2999366f72498cdbc43e6f2fc184afe30
+ Output = ed84ad3f31a552f0456e58935fcc0a3039db42e7f356dcb32aa6d487b6b
+ 815a07d5813641fb1398c03ddab5763874357
+
+A.4.1.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 02def6f418e3484f67a124a2ce1bfb19de7a4af568ede6a1ebb
+ 2733882510ddd43d05f2b1ab5187936a55e50a847a8b900
+ EvaluationElement = 034e9b9a2960b536f2ef47d8608b21597ba400d5abfa1825
+ fd21c36b75f927f396bf3716c96129d1fa4a77fa1d479c8d7b
+ Output = dd4f29da869ab9355d60617b60da0991e22aaab243a3460601e48b07585
+ 9d1c526d36597326f1b985778f781a1682e75
+
+A.4.2. VOPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 051646b9e6e7a71ae27c1e1d0b87b4381db6d3595eeeb1adb41579adbf992
+ f4278f9016eafc944edaa2b43183581779d
+ pkSm = 031d689686c611991b55f1a1d8f4305ccd6cb719446f660a30db61b7aa87b
+ 46acf59b7c0d4a9077b3da21c25dd482229a0
+
+A.4.2.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 02d338c05cbecb82de13d6700f09cb61190543a7b7e2c6cd4fc
+ a56887e564ea82653b27fdad383995ea6d02cf26d0e24d9
+ EvaluationElement = 02a7bba589b3e8672aa19e8fd258de2e6aae20101c8d7612
+ 46de97a6b5ee9cf105febce4327a326255a3c604f63f600ef6
+ Proof = bfc6cf3859127f5fe25548859856d6b7fa1c7459f0ba5712a806fc091a30
+ 00c42d8ba34ff45f32a52e40533efd2a03bc87f3bf4f9f58028297ccb9ccb18ae718
+ 2bcd1ef239df77e3be65ef147f3acf8bc9cbfc5524b702263414f043e3b7ca2e
+ ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
+ c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ Output = 3333230886b562ffb8329a8be08fea8025755372817ec969d114d1203d0
+ 26b4a622beab60220bf19078bca35a529b35c
+
+A.4.2.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 02f27469e059886f221be5f2cca03d2bdc61e55221721c3b3e5
+ 6fc012e36d31ae5f8dc058109591556a6dbd3a8c69c433b
+ EvaluationElement = 03f16f903947035400e96b7f531a38d4a07ac89a80f89d86
+ a1bf089c525a92c7f4733729ca30c56ce78b1ab4f7d92db8b4
+ Proof = d005d6daaad7571414c1e0c75f7e57f2113ca9f4604e84bc90f9be52da89
+ 6fff3bee496dcde2a578ae9df315032585f801fb21c6080ac05672b291e575a40295
+ b306d967717b28e08fcc8ad1cab47845d16af73b3e643ddcc191208e71c64630
+ ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
+ c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ Output = b91c70ea3d4d62ba922eb8a7d03809a441e1c3c7af915cbc2226f485213
+ e895942cd0f8580e6d99f82221e66c40d274f
+
+A.4.2.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364,803d955f0e073a04aa5d92b3fb739f5
+ 6f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ BlindedElement = 02d338c05cbecb82de13d6700f09cb61190543a7b7e2c6cd4fc
+ a56887e564ea82653b27fdad383995ea6d02cf26d0e24d9,02fa02470d7f151018b4
+ 1e82223c32fad824de6ad4b5ce9f8e9f98083c9a726de9a1fc39d7a0cb6f4f188dd9
+ cea01474cd
+ EvaluationElement = 02a7bba589b3e8672aa19e8fd258de2e6aae20101c8d7612
+ 46de97a6b5ee9cf105febce4327a326255a3c604f63f600ef6,028e9e115625ff4c2
+ f07bf87ce3fd73fc77994a7a0c1df03d2a630a3d845930e2e63a165b114d98fe34e6
+ 1b68d23c0b50a
+ Proof = 6d8dcbd2fc95550a02211fb78afd013933f307d21e7d855b0b1ed0af7807
+ 6d8137ad8b0a1bfa05676d325249c1dbb9a52bd81b1c2b7b0efc77cf7b278e1c947f
+ 6283f1d4c513053fc0ad19e026fb0c30654b53d9cea4b87b037271b5d2e2d0ea
+ ProofRandomScalar = a097e722ed2427de86966910acba9f5c350e8040f828bf6c
+ eca27405420cdf3d63cb3aef005f40ba51943c8026877963
+ Output = 3333230886b562ffb8329a8be08fea8025755372817ec969d114d1203d0
+ 26b4a622beab60220bf19078bca35a529b35c,b91c70ea3d4d62ba922eb8a7d03809
+ a441e1c3c7af915cbc2226f485213e895942cd0f8580e6d99f82221e66c40d274f
+
+A.4.3. POPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 5b2690d6954b8fbb159f19935d64133f12770c00b68422559c65431942d72
+ 1ff79d47d7a75906c30b7818ec0f38b7fb2
+ pkSm = 02f00f0f1de81e5d6cf18140d4926ffdc9b1898c48dc49657ae36eb1e45de
+ b8b951aaf1f10c82d2eaa6d02aafa3f10d2b6
+
+A.4.3.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Info = 7465737420696e666f
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 03859b36b95e6564faa85cd3801175eda2949707f6aa0640ad0
+ 93cbf8ad2f58e762f08b56b2a1b42a64953aaf49cbf1ae3
+ EvaluationElement = 0220710e2e00306453f5b4f574cb6a512453f35c45080d09
+ 373e190c19ce5b185914fbf36582d7e0754bb7c8b683205b91
+ Proof = 82a17ef41c8b57f1e3122311b4d5cd39a63df0f67443ef18d961f9b659c1
+ 601ced8d3c64b294f604319ca80230380d437a49c7af0d620e22116669c008ebb767
+ d90283d573b49cdb49e3725889620924c2c4b047a2a6225a3ba27e640ebddd33
+ ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
+ c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ Output = 0188653cfec38119a6c7dd7948b0f0720460b4310e40824e048bf82a165
+ 27303ed449a08caf84272c3bbc972ede797df
+
+A.4.3.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364
+ BlindedElement = 03f7efcb4aaf000263369d8a0621cb96b81b3206e99876de2a0
+ 0699ed4c45acf3969cd6e2319215395955d3f8d8cc1c712
+ EvaluationElement = 034993c818369927e74b77c400376fd1ae29b6ac6c6ddb77
+ 6cf10e4fbc487826531b3cf0b7c8ca4d92c7af90c9def85ce6
+ Proof = 693471b5dff0cd6a5c00ea34d7bf127b2795164e3bdb5f39a1e5edfbd13e
+ 443bc516061cd5b8449a473c2ceeccada9f3e5b57302e3d7bc5e28d38d6e3a3056e1
+ e73b6cc030f5180f8a1ffa45aa923ee66d2ad0a07b500f2acc7fb99b5506465c
+ ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
+ c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ Output = ff2a527a21cc43b251a567382677f078c6e356336aec069dea8ba369953
+ 43ca3b33bb5d6cf15be4d31a7e6d75b30d3f5
+
+A.4.3.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
+ 889d89dbfa691d1cde91517fa222ed7ad364,803d955f0e073a04aa5d92b3fb739f5
+ 6f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
+ BlindedElement = 03859b36b95e6564faa85cd3801175eda2949707f6aa0640ad0
+ 93cbf8ad2f58e762f08b56b2a1b42a64953aaf49cbf1ae3,021a65d618d645f1a20b
+ c33b06deaa7e73d6d634c8a56a3d02b53a732b69a5c53c5a207ea33d5afdcde9a22d
+ 59726bce51
+ EvaluationElement = 0220710e2e00306453f5b4f574cb6a512453f35c45080d09
+ 373e190c19ce5b185914fbf36582d7e0754bb7c8b683205b91,02017657b315ec65e
+ f861505e596c8645d94685dd7602cdd092a8f1c1c0194a5d0485fe47d071d972ab51
+ 4370174cc23f5
+ Proof = 4a0b2fe96d5b2a046a0447fe079b77859ef11a39a3520d6ff7c626aad9b4
+ 73b724fb0cf188974ec961710a62162a83e97e0baa9eeada73397032d928b3e97b1e
+ a92ad9458208302be3681b8ba78bcc17745bac00f84e0fdc98a6a8cba009c080
+ ProofRandomScalar = a097e722ed2427de86966910acba9f5c350e8040f828bf6c
+ eca27405420cdf3d63cb3aef005f40ba51943c8026877963
+ Output = 0188653cfec38119a6c7dd7948b0f0720460b4310e40824e048bf82a165
+ 27303ed449a08caf84272c3bbc972ede797df,ff2a527a21cc43b251a567382677f0
+ 78c6e356336aec069dea8ba36995343ca3b33bb5d6cf15be4d31a7e6d75b30d3f5
+
+A.5. P521-SHA512
+
+A.5.1. OPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 0153441b8faedb0340439036d6aed06d1217b34c42f17f8db4c5cc610a4a9
+ 55d698a688831b16d0dc7713a1aa3611ec60703bffc7dc9c84e3ed673b3dbe1d5fcc
+ ea6
+
+A.5.1.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 0300e78bf846b0e1e1a3c320e353d758583cd876df56100a3a1
+ e62bacba470fa6e0991be1be80b721c50c5fd0c672ba764457acc18c6200704e9294
+ fbf28859d916351
+ EvaluationElement = 030166371cf827cb2fb9b581f97907121a16e2dc5d8b10ce
+ 9f0ede7f7d76a0d047657735e8ad07bcda824907b3e5479bd72cdef6b839b967ba5c
+ 58b118b84d26f2ba07
+ Output = 26232de6fff83f812adadadb6cc05d7bbeee5dca043dbb16b03488abb99
+ 81d0a1ef4351fad52dbd7e759649af393348f7b9717566c19a6b8856284d69375c80
+ 9
+
+A.5.1.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 0300c28e57e74361d87e0c1874e5f7cc1cc796d61f9cad50427
+ cf54655cdb455613368d42b27f94bf66f59f53c816db3e95e68e1b113443d66a99b3
+ 693bab88afb556b
+ EvaluationElement = 0301ad453607e12d0cc11a3359332a40c3a254eaa1afc642
+ 96528d55bed07ba322e72e22cf3bcb50570fd913cb54f7f09c17aff8787af75f6a7f
+ af5640cbb2d9620a6e
+ Output = ad1f76ef939042175e007738906ac0336bbd1d51e287ebaa66901abdd32
+ 4ea3ffa40bfc5a68e7939c2845e0fd37a5a6e76dadb9907c6cc8579629757fd4d04b
+ a
+
+A.5.2. VOPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 015c7fc1b4a0b1390925bae915bd9f3d72009d44d9241b962428aad5d13f2
+ 2803311e7102632a39addc61ea440810222715c9d2f61f03ea424ec9ab1fe5e31cf9
+ 238
+ pkSm = 0301505d646f6e4c9102451eb39730c4ba1c4087618641edbdba4a60896b0
+ 7fd0c9414ce553cbf25b81dfcca50a8f6724ab7a2bc4d0cf736967a287bb6084cc06
+ 78ac0
+
+A.5.2.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 0301d6e4fb545e043ddb6aee5d5ceeee1b44102615ab04430c2
+ 7dd0f56988dedcb1df32ef384f160e0e76e718605f14f3f582f9357553d153b99679
+ 5b4b3628a4f6380
+ EvaluationElement = 03013fdeaf887f3d3d283a79e696a54b66ff0edcb559265e
+ 204a958acf840e0930cc147e2a6835148d8199eebc26c03e9394c9762a1c991dde40
+ bca0f8ca003eefb045
+ Proof = 0077fcc8ec6d059d7759b0a61f871e7c1dadc65333502e09a51994328f79
+ e5bda3357b9a4f410a1760a3612c2f8f27cb7cb032951c047cc66da60da583df7b24
+ 7edd0188e5eb99c71799af1d80d643af16ffa1545acd9e9233fbb370455b10eb257e
+ a12a1667c1b4ee5b0ab7c93d50ae89602006960f083ca9adc4f6276c0ad60440393c
+ ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
+ 3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 5e003d9b2fb540b3d4bab5fedd154912246da1ee5e557afd8f56415faa1
+ a0fadff6517da802ee254437e4f60907b4cda146e7ba19e249eef7be405549f62954
+ b
+
+A.5.2.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 03005b05e656cb609ce5ff5faf063bb746d662d67bbd07c0626
+ 38396f52f0392180cf2365cabb0ece8e19048961d35eeae5d5fa872328dce98df076
+ ee154dd191c615e
+ EvaluationElement = 0301b19fcf482b1fff04754e282292ed736c5f0aa080d4f4
+ 2663cd3a416c6596f03129e8e096d8671fe5b0d19838312c511d2ce08d431e43e3ef
+ 06199d8cab7426238d
+ Proof = 01ec9fece444caa6a57032e8963df0e945286f88fbdf233fb5101f0924f7
+ ea89c47023f5f72f240e61991fd33a299b5b38c45a5e2dd1a67b072e59dfe86708a3
+ 59c701e38d383c60cf6969463bcf13251bedad47b7941f52e409a3591398e2792441
+ 0b18a301c0e19f527cad504fa08388050ac634e1b05c5216d337742f2754e1fc502f
+ ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
+ 3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = fa15eebba81ecf40954f7135cb76f69ef22c6bae394d1a4362f9b03066b
+ 54b6604d39f2e53369ca6762a3d9787e230e832aa85955af40ecb8deebb009a8cf47
+ 4
+
+A.5.2.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364,015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e073a04aa5d92b3fb7
+ 39f56f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b
+ 1
+ BlindedElement = 0301d6e4fb545e043ddb6aee5d5ceeee1b44102615ab04430c2
+ 7dd0f56988dedcb1df32ef384f160e0e76e718605f14f3f582f9357553d153b99679
+ 5b4b3628a4f6380,0301403b597538b939b450c93586ba275f9711ba07e42364bac1
+ d5769c6824a8b55be6f9a536df46d952b11ab2188363b3d6737635d9543d4dba14a6
+ e19421b9245bf5
+ EvaluationElement = 03013fdeaf887f3d3d283a79e696a54b66ff0edcb559265e
+ 204a958acf840e0930cc147e2a6835148d8199eebc26c03e9394c9762a1c991dde40
+ bca0f8ca003eefb045,03001f96424497e38c46c904978c2fa1636c5c3dd2e634a85
+ d8a7265977c5dce1f02c7e6c118479f0751767b91a39cce6561998258591b5d7c1bb
+ 02445a9e08e4f3e8d
+ Proof = 00b4d215c8405e57c7a4b53398caf55f1f1623aaeb22408ddb9ea2913090
+ 9b3f95dbb1ff366e81e86e918f9f2fd8b80dbb344cd498c9499d112905e585417e00
+ 68c600fe5dea18b389ef6c4cc062935607b8ccbbb9a84fba3143868a3e8a58efa0bf
+ 6ca642804d09dc06e980f64837811227c4267b217f1099a4e28b0854f4e5ee659796
+ ProofRandomScalar = 01ec21c7bb69b0734cb48dfd68433dd93b0fa097e722ed24
+ 27de86966910acba9f5c350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
+ 51943c8026877963
+ Output = 5e003d9b2fb540b3d4bab5fedd154912246da1ee5e557afd8f56415faa1
+ a0fadff6517da802ee254437e4f60907b4cda146e7ba19e249eef7be405549f62954
+ b,fa15eebba81ecf40954f7135cb76f69ef22c6bae394d1a4362f9b03066b54b6604
+ d39f2e53369ca6762a3d9787e230e832aa85955af40ecb8deebb009a8cf474
+
+A.5.3. POPRF Mode
+
+ Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
+ 3a3
+ KeyInfo = 74657374206b6579
+ skSm = 014893130030ce69cf714f536498a02ff6b396888f9bb507985c32928c442
+ 7d6d39de10ef509aca4240e8569e3a88debc0d392e3361bcd934cb9bdd59e339dff7
+ b27
+ pkSm = 0301de8ceb9ffe9237b1bba87c320ea0bebcfc3447fe6f278065c6c69886d
+ 692d1126b79b6844f829940ace9b52a5e26882cf7cbc9e57503d4cca3cd834584729
+ f812a
+
+A.5.3.1. Test Vector 1, Batch Size 1
+
+ Input = 00
+ Info = 7465737420696e666f
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 020095cff9d7ecf65bdfee4ea92d6e748d60b02de34ad98094f
+ 82e25d33a8bf50138ccc2cc633556f1a97d7ea9438cbb394df612f041c485a515849
+ d5ebb2238f2f0e2
+ EvaluationElement = 0301408e9c5be3ffcc1c16e5ae8f8aa68446223b0804b119
+ 62e856af5a6d1c65ebbb5db7278c21db4e8cc06d89a35b6804fb1738a295b691638a
+ f77aa1327253f26d01
+ Proof = 0106a89a61eee9dd2417d2849a8e2167bc5f56e3aed5a3ff23e22511fa1b
+ 37a29ed44d1bbfd6907d99cfbc558a56aec709282415a864a281e49dc53792a4a638
+ a0660034306d64be12a94dcea5a6d664cf76681911c8b9a84d49bf12d4893307ec14
+ 436bd05f791f82446c0de4be6c582d373627b51886f76c4788256e3da7ec8fa18a86
+ ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
+ 3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 808ae5b87662eaaf0b39151dd85991b94c96ef214cb14a68bf5c1439548
+ 82d330da8953a80eea20788e552bc8bbbfff3100e89f9d6e341197b122c46a208733
+ b
+
+A.5.3.2. Test Vector 2, Batch Size 1
+
+ Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364
+ BlindedElement = 030112ea89cf9cf589496189eafc5f9eb13c9f9e170d6ecde7c
+ 5b940541cb1a9c5cfeec908b67efe16b81ca00d0ce216e34b3d5f46a658d3fd8573d
+ 671bdb6515ed508
+ EvaluationElement = 0200ebc49df1e6fa61f412e6c391e6f074400ecdd2f56c4a
+ 8c03fe0f91d9b551f40d4b5258fd891952e8c9b28003bcfa365122e54a5714c8949d
+ 5d202767b31b4bf1f6
+ Proof = 0082162c71a7765005cae202d4bd14b84dae63c29067e886b82506992bd9
+ 94a1c3aac0c1c5309222fe1af8287b6443ed6df5c2e0b0991faddd3564c73c7597ae
+ cd9a003b1f1e3c65f28e58ab4e767cfb4adbcaf512441645f4c2aed8bf67d132d966
+ 006d35fa71a34145414bf3572c1de1a46c266a344dd9e22e7fb1e90ffba1caf556d9
+ ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
+ 3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
+ e45c405d1348b7b1
+ Output = 27032e24b1a52a82ab7f4646f3c5df0f070f499db98b9c5df33972bd5af
+ 5762c3638afae7912a6c1acdb1ae2ab2fa670bd5486c645a0e55412e08d33a4a0d6e
+ 3
+
+A.5.3.3. Test Vector 3, Batch Size 2
+
+ Input = 00,5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
+ Info = 7465737420696e666f
+ Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
+ 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
+ d364,015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e073a04aa5d92b3fb7
+ 39f56f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b
+ 1
+ BlindedElement = 020095cff9d7ecf65bdfee4ea92d6e748d60b02de34ad98094f
+ 82e25d33a8bf50138ccc2cc633556f1a97d7ea9438cbb394df612f041c485a515849
+ d5ebb2238f2f0e2,0201a328cf9f3fdeb86b6db242dd4cbb436b3a488b70b72d2fbb
+ d1e5f50d7b0878b157d6f278c6a95c488f3ad52d6898a421658a82fe7ceb000b01ae
+ dea7967522d525
+ EvaluationElement = 0301408e9c5be3ffcc1c16e5ae8f8aa68446223b0804b119
+ 62e856af5a6d1c65ebbb5db7278c21db4e8cc06d89a35b6804fb1738a295b691638a
+ f77aa1327253f26d01,020062ab51ac3aa829e0f5b7ae50688bcf5f63a18a83a6e0d
+ a538666b8d50c7ea2b4ef31f4ac669302318dbebe46660acdda695da30c22cee7ca2
+ 1f6984a720504502e
+ Proof = 00731738844f739bca0cca9d1c8bea204bed4fd00285785738b985763741
+ de5cdfa275152d52b6a2fdf7792ef3779f39ba34581e56d62f78ecad5b7f8083f384
+ 961501cd4b43713253c022692669cf076b1d382ecd8293c1de69ea569737f37a2477
+ 2ab73517983c1e3db5818754ba1f008076267b8058b6481949ae346cdc17a8455fe2
+ ProofRandomScalar = 01ec21c7bb69b0734cb48dfd68433dd93b0fa097e722ed24
+ 27de86966910acba9f5c350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
+ 51943c8026877963
+ Output = 808ae5b87662eaaf0b39151dd85991b94c96ef214cb14a68bf5c1439548
+ 82d330da8953a80eea20788e552bc8bbbfff3100e89f9d6e341197b122c46a208733
+ b,27032e24b1a52a82ab7f4646f3c5df0f070f499db98b9c5df33972bd5af5762c36
+ 38afae7912a6c1acdb1ae2ab2fa670bd5486c645a0e55412e08d33a4a0d6e3
+
+Acknowledgements
+
+ This document resulted from the work of the Privacy Pass team
+ [PrivacyPass]. 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.
+
+Authors' Addresses
+
+ Alex Davidson
+ Brave Software
+ Email: alex.davidson92@gmail.com
+
+
+ Armando Faz-Hernandez
+ Cloudflare, Inc.
+ 101 Townsend St
+ San Francisco, CA
+ United States of America
+ Email: armfazh@cloudflare.com
+
+
+ Nick Sullivan
+ Cloudflare, Inc.
+ 101 Townsend St
+ San Francisco, CA
+ United States of America
+ Email: nicholas.sullivan+ietf@gmail.com
+
+
+ Christopher A. Wood
+ Cloudflare, Inc.
+ 101 Townsend St
+ San Francisco, CA
+ United States of America
+ Email: caw@heapingbits.net