Internet-Draft OPRFs October 2023
Davidson, et al. Expires 12 April 2024 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-irtf-cfrg-voprf-latest
Published:
Intended Status:
Informational
Expires:
Authors:
A. Davidson
Brave Software
A. Faz-Hernandez
Cloudflare, Inc.
N. Sullivan
Cloudflare, Inc.
C. A. Wood
Cloudflare, Inc.

Oblivious Pseudorandom Functions (OPRFs) using Prime-Order Groups

Abstract

An Oblivious Pseudorandom Function (OPRF) is a two-party protocol between client and server for computing the output of a Pseudorandom Function (PRF). The server provides the PRF 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.

Discussion Venues

This note is to be removed before publishing as an RFC.

Source for this draft and an issue tracker can be found at https://github.com/cfrg/draft-irtf-cfrg-voprf.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 12 April 2024.

Table of Contents

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, where the server holds a PRF key k and the client holds some input x. The protocol allows both parties to cooperate in computing F(k, x) such that the client learns F(k, x) without learning anything about k; and the server does not learn anything about x or F(k, x). A Verifiable OPRF (VOPRF) is an OPRF wherein the server also proves to the client that F(k, x) was produced by the key k corresponding to the server's public key, which the client knows. A Partially-Oblivious PRF (POPRF) is a variant of a VOPRF wherein client and server interact in computing F(k, x, y), for some PRF F with server-provided key k, client-provided input x, and public input y, and client receives proof that F(k, x, y) was computed using k corresponding to the public key that the client knows. A POPRF with fixed input y is functionally equivalent to a VOPRF.

OPRFs have a variety of applications, including: password-protected secret sharing schemes [JKKX16], privacy-preserving password stores [SJKS17], and password-authenticated key exchange or PAKE [OPAQUE]. Verifiable OPRFs are necessary in some applications such as Privacy Pass [PRIVACYPASS]. 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. Change log

draft-21:

  • Apply more IRSG review comments.

draft-20:

  • Address IRSG comments.

draft-19:

  • Fix error.

draft-18:

  • Apply editorial suggestions from CFRG chair review.

draft-17:

  • Change how suites are identified and finalize test vectors.

  • Apply editorial suggestions from IRTF chair review.

draft-16:

  • Apply editorial suggestions from document shepherd.

draft-15:

  • Apply editorial suggestions from CFRG RGLC.

draft-14:

  • Correct current state of formal analysis for the VOPRF protocol variant.

draft-13:

  • Editorial improvements based on Crypto Panel Review.

draft-12:

  • Small editorial fixes

draft-11:

  • Change Evaluate to BlindEvaluate, and add Evaluate for PRF evaluation

draft-10:

  • Editorial improvements

draft-09:

  • Split syntax for OPRF, VOPRF, and POPRF functionalities.

  • Make Blind function fallible for invalid private and public inputs.

  • Specify key generation.

  • Remove serialization steps from core protocol functions.

  • Refactor protocol presentation for clarity.

  • Simplify security considerations.

  • Update application interface considerations.

  • Update test vectors.

draft-08:

  • Adopt partially-oblivious PRF construction from [TCRSTW21].

  • Update P-384 suite to use SHA-384 instead of SHA-512.

  • Update test vectors.

  • Apply various editorial changes.

draft-07:

  • Bind blinding mechanism to mode (additive for verifiable mode and multiplicative for base mode).

  • Add explicit errors for deserialization.

  • Document explicit errors and API considerations.

  • Adopt SHAKE-256 for decaf448 ciphersuite.

  • Normalize HashToScalar functionality for all ciphersuites.

  • Refactor and generalize DLEQ proof functionality and domain separation tags for use in other protocols.

  • Update test vectors.

  • Apply various editorial changes.

draft-06:

  • Specify of group element and scalar serialization.

  • Remove info parameter from the protocol API and update domain separation guidance.

  • Fold Unblind function into Finalize.

  • Optimize ComputeComposites for servers (using knowledge of the private key).

  • Specify deterministic key generation method.

  • Update test vectors.

  • Apply various editorial changes.

draft-05:

  • Move to ristretto255 and decaf448 ciphersuites.

  • Clean up ciphersuite definitions.

  • Pin domain separation tag construction to draft version.

  • Move key generation outside of context construction functions.

  • Editorial changes.

draft-04:

  • Introduce Client and Server contexts for controlling verifiability and required functionality.

  • Condense API.

  • Remove batching from standard functionality (included as an extension)

  • Add Curve25519 and P-256 ciphersuites for applications that prevent strong-DH oracle attacks.

  • Provide explicit prime-order group API and instantiation advice for each ciphersuite.

  • Proof-of-concept implementation in sage.

  • Remove privacy considerations advice as this depends on applications.

draft-03:

  • Certify public key during VerifiableFinalize.

  • Remove protocol integration advice.

  • Add text discussing how to perform domain separation.

  • Drop OPRF_/VOPRF_ prefix from algorithm names.

  • Make prime-order group assumption explicit.

  • Changes to algorithms accepting batched inputs.

  • Changes to construction of batched DLEQ proofs.

  • Updated ciphersuites to be consistent with hash-to-curve and added OPRF specific ciphersuites.

draft-02:

  • Added section discussing cryptographic security and static DH oracles.

  • Updated batched proof algorithms.

draft-01:

  • Updated ciphersuites to be in line with https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-04.

  • Made some necessary modular reductions more explicit.

1.2. Requirements

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

1.3. 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 non-negative 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 as U[j] such that 0 <= j < N.

All algorithms and procedures described in this document are laid out in a Python-like pseudocode. Each function takes a set of inputs and parameters and produces a set of output values. Parameters become constant values once the protocol variant and the ciphersuite are fixed.

The PrivateInput data type refers to inputs that are known only to the client in the protocol, whereas the PublicInput data type refers to inputs that are known to both client and server in the protocol. Both PrivateInput and PublicInput are opaque byte strings of arbitrary length no larger than 216 - 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 pseudorandom function evaluation as the output of the protocol.

  • Server: Computes the pseudorandom function using a private key. Learns nothing about the client's input or output.

2. Preliminaries

The protocols in this document have two primary dependencies:

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 Group for performing all mathematical operations. In prime-order groups, any element (other than the identity) can generate the other elements of the group. Usually, one element is fixed and defined as the group generator. Such groups are uniquely determined by the choice of the prime p that defines the order of the group. (There may, however, exist different representations of the group for a single p. Section 4 lists specific groups which indicate both order and representation.)

The fundamental group operation is addition + with identity element I. For any elements A and B of the group, A + B = B + A is also a member of the group. Also, for any A in the group, there exists an element -A such that A + (-A) = (-A) + A = I. Scalar multiplication by r is equivalent to the repeated application of the group operation on an element A with itself r-1 times, this is denoted as r*A = A + ... + A. For any element A, p*A=I. The case when the scalar multiplication is performed on the group generator is denoted as ScalarMultGen(r). Given two elements A and B, the discrete logarithm problem is to find an integer k such that B = k*A. Thus, k is the discrete logarithm of B with respect to the base A. The set of scalars corresponds to GF(p), a prime field of order p, and are represented as the set of integers defined by {0, 1, ..., p-1}. This document uses types Element and Scalar to denote elements of the group and its set of scalars, respectively.

We now detail a number of member functions that can be invoked on a prime-order group.

  • Order(): Outputs the order of the group (i.e. p).

  • Identity(): Outputs the identity element of the group (i.e. I).

  • Generator(): Outputs the generator element of the group.

  • HashToGroup(x): Deterministically maps an array of bytes x to an element of Group. The map must ensure that, for any adversary receiving R = HashToGroup(x), it is computationally difficult to reverse the mapping. This function is optionally parameterized by a domain separation tag (DST); see Section 4. Security properties of this function are described in [I-D.irtf-cfrg-hash-to-curve].

  • 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 [I-D.irtf-cfrg-hash-to-curve], Section 10.5.

  • RandomScalar(): Chooses at random a non-zero 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 a Scalar s to a canonical byte array buf of fixed length Ns.

  • DeserializeScalar(buf): Attempts to map a byte array buf to a 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 PRNG. The description is split into two sub-sections: one for generating the proof, which is done by servers in the verifiable protocols, and another for verifying the proof, which is done by clients in the protocol.

2.2.1. Proof Generation

Generating a proof is done with the GenerateProof function, defined below. Given elements A and B, two non-empty lists of elements C and D of length m, and a scalar k; this function produces a proof that k*A == B and k*C[i] == D[i] for each i in [0, ..., m - 1]. The output is a value of type Proof, which is a tuple of two Scalar values. We use the notation proof[0] and proof[1] to denote the first and second elements in this tuple, respectively.

GenerateProof accepts lists of inputs to amortize the cost of proof generation. Applications can take advantage of this functionality to produce a single, constant-sized proof for m DLEQ inputs, rather than m proofs for m DLEQ inputs.

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, defined below. This function takes elements A and B, two non-empty lists of elements C and D of length m, and a Proof value output from GenerateProof. It outputs a single boolean value indicating whether or not the proof is valid for the given DLEQ inputs. Note this function can verify proofs on lists of inputs whenever the proof was generated as a batched DLEQ proof with the same inputs.

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 involve two messages between client and server but 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 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 it used to produce the server's public key, pkS, which the client receives as input to the protocol. This proof does not reveal the server's private key to the client. This interaction is shown below.

    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 a public input info that is used in computing the pseudorandom function. That is, the client and server interact to compute output = F(skS, input, info) as is shown below.

    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, described in Section 3.2 and Section 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):

Table 1: Identifiers for protocol variants.
Mode Value
modeOPRF 0x00
modeVOPRF 0x01
modePOPRF 0x02

Additionally, each protocol variant is instantiated with a ciphersuite, or suite. Each ciphersuite is identified with an ASCII string identifier, referred to as identifier; see 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 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 Ns bytes generated from a cryptographically secure random number generator and an optional (possibly empty) info string. The constant Ns corresponds to the size in bytes of a serialized Scalar and is defined in Section 2.1. 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[Ns]
  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 client and server in Section 3.2.

Applications serialize protocol messages between client and server for transmission. Elements and scalars are serialized to byte arrays, and values of type Proof are serialized as the concatenation of two serialized scalars. Deserializing these values can fail, in which case the application MUST abort the protocol raising a DeserializeError failure.

Applications MUST check that input Element values received over the wire are not the group identity element. This check is handled after deserializing Element values; see 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 which 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 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 which 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 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 which 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:

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 [RISTRETTO] for the Group and SHA-512 for the Hash function. The value of the ciphersuite identifier is "ristretto255-SHA512".

  • Group: ristretto255 [RISTRETTO]

    • Order(): Return 2^252 + 27742317777372353535851937790883648493 (see [RISTRETTO])

    • Identity(): As defined in [RISTRETTO].

    • Generator(): As defined in [RISTRETTO].

    • HashToGroup(): Use hash_to_ristretto255 [I-D.irtf-cfrg-hash-to-curve] with DST = "HashToGroup-" || contextString, and expand_message = expand_message_xmd using SHA-512.

    • HashToScalar(): Compute uniform_bytes using expand_message = expand_message_xmd, DST = "HashToScalar-" || contextString, and output length 64, interpret uniform_bytes as a 512-bit integer in little-endian order, and reduce the integer modulo Group.Order().

    • ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().

    • RandomScalar(): Implemented by returning a uniformly random Scalar in the range [0, G.Order() - 1]. Refer to Section 4.7 for implementation guidance.

    • SerializeElement(A): Implemented using the 'Encode' function from Section 4.3.2 of [RISTRETTO]; Ne = 32.

    • DeserializeElement(buf): Implemented using the 'Decode' function from Section 4.3.1 of [RISTRETTO]. 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 [RISTRETTO] for the Group and SHAKE-256 for the Hash function. The value of the ciphersuite identifier is "decaf448-SHAKE256".

  • Group: decaf448 [RISTRETTO]

    • Order(): Return 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885

    • Identity(): As defined in [RISTRETTO].

    • Generator(): As defined in [RISTRETTO].

    • 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 [I-D.irtf-cfrg-hash-to-curve] 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 [RISTRETTO]; Ne = 56.

    • DeserializeElement(buf): Implemented using the 'Decode' function from Section 5.3.1 of [RISTRETTO]. 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 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551.

    • 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_ [I-D.irtf-cfrg-hash-to-curve] and DST = "HashToGroup-" || contextString.

    • HashToScalar(): Use hash_to_field from [I-D.irtf-cfrg-hash-to-curve] using L = 48, expand_message_xmd with SHA-256, DST = "HashToScalar-" || contextString, and prime modulus equal to Group.Order().

    • ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().

    • SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String method according to [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 performs 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 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973.

    • 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_ [I-D.irtf-cfrg-hash-to-curve] and DST = "HashToGroup-" || contextString.

    • HashToScalar(): Use hash_to_field from [I-D.irtf-cfrg-hash-to-curve] using L = 72, expand_message_xmd with SHA-384, DST = "HashToScalar-" || contextString, and prime modulus equal to Group.Order().

    • ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().

    • SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String method according to [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 performs 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 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409.

    • 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_ [I-D.irtf-cfrg-hash-to-curve] and DST = "HashToGroup-" || contextString.

    • HashToScalar(): Use hash_to_field from [I-D.irtf-cfrg-hash-to-curve] using L = 98, expand_message_xmd with SHA-512, DST = "HashToScalar-" || contextString, and prime modulus equal to Group.Order().

    • ScalarInverse(s): Returns the multiplicative inverse of input Scalar s mod Group.Order().

    • SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String method according to [SEC1]; Ne = 67.

    • DeserializeElement(buf): Implemented by attempting to deserialize a 49 byte input string to a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to [SEC1], and then performs 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, that maps inputs to group elements. In the elliptic curve setting, this deterministically maps inputs (as byte arrays) to uniformly chosen points on the curve.

In the security proof of the construction Hash is modeled as a random oracle. This implies that any instantiation of HashToGroup must be pre-image and collision resistant. In Section 4 we give instantiations of this functionality based on the functions described in [I-D.irtf-cfrg-hash-to-curve]. Consequently, any OPRF implementation must adhere to the implementation and security considerations discussed in [I-D.irtf-cfrg-hash-to-curve] 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 as follows:

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 - 2b| 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 [I-D.irtf-cfrg-hash-to-curve], 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 216-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 elements and scalars. However, implementations can instead operate over group elements and scalars internally, and only expose interfaces that operate with an application-specific format of messages.

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:

There are other explicit errors generated in this specification; however, they occur with negligible probability in practice. We note them here for completeness.

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 [I-D.irtf-cfrg-hash-to-curve], 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 non-malleable (i.e. we cannot compute a new evaluation of F from an existing evaluation). A genuinely random function will be non-malleable with high probability, and so a pseudorandom function must be non-malleable to maintain indistinguishability.

  • Unconditional input secrecy: The server does not learn anything about the client input x, even with unbounded computation.

In other words, an attacker with infinite computing power cannot recover any information about the client's private input x from an invocation of the protocol.

Essentially, input secrecy is the property that, even if the server learns the client's private input x at some point in the future, the server cannot link any particular PRF evaluation to x. This property is also known as unlinkability [DGSTV18].

Beyond client input secret, in the OPRF protocol, the server learns nothing about the output y of the function, nor does the client learn anything about the server's private key k.

For the VOPRF and POPRF protocol variants, there is an additional security property:

  • Verifiable: The client must only complete execution of the protocol if it can successfully assert that the output it computes is correct. This is taken with respect to the private key held by the server.

Any VOPRF or POPRF that satisfies the 'verifiable' security property is known as 'verifiable'. In practice, the notion of verifiability requires that the server commits to the key before the actual protocol execution takes place. Then the client verifies that the server has used the key in the protocol using this commitment. In the following, we may also refer to this commitment as a public key.

Finally, the POPRF variant also has the following security property:

  • Partial obliviousness: The client and server must be able to perform the PRF on client's private input and public input. Both client and server know the public input, but similar to the OPRF and VOPRF protocols, the server learns nothing about the client's private input or the output of the function, and the client learns nothing about the server's private key.

This property becomes useful when dealing with key management operations such as the rotation of server's keys. Note that partial obliviousness only applies to the POPRF variant because neither the OPRF nor VOPRF variants accept public input to the protocol.

Since the POPRF variant has a different syntax than the OPRF and VOPRF variants, i.e., y = F(k, x, info), the pseudorandomness property is generalized:

  • Pseudorandomness: For a random sampling of k, F is pseudorandom if the output y = F(k, x, info) on any input pairs (x, info) is indistinguishable from uniformly sampling any element in F's range.

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; and

  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 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 which has multiple OPRF applications should distinguish client inputs to ensure the OPRF results are separate. Guidance for constructing info can be found in [I-D.irtf-cfrg-hash-to-curve], 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. 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.

9. References

9.1. Normative References

[I-D.irtf-cfrg-hash-to-curve]
Faz-Hernandez, A., Scott, S., Sullivan, N., Wahby, R. S., and C. A. Wood, "Hashing to Elliptic Curves", Work in Progress, Internet-Draft, draft-irtf-cfrg-hash-to-curve-16, , <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-16>.
[KEYAGREEMENT]
Barker, E., Chen, L., Roginsky, A., Vassilev, A., and R. Davis, "Recommendation for pair-wise key-establishment schemes using discrete logarithm cryptography", National Institute of Standards and Technology, DOI 10.6028/nist.sp.800-56ar3, , <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, , <https://www.rfc-editor.org/rfc/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, , <https://www.rfc-editor.org/rfc/rfc8017>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RISTRETTO]
de Valence, H., Grigg, J., Hamburg, M., Lovecruft, I., Tankersley, G., and F. Valsorda, "The ristretto255 and decaf448 Groups", Work in Progress, Internet-Draft, draft-irtf-cfrg-ristretto255-decaf448-08, , <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-08>.

9.2. Informative References

[BG04]
Brown, D. and R. Gallant, "The Static Diffie-Hellman Problem", <https://eprint.iacr.org/2004/306>.
[ChaumPedersen]
Chaum, D. and T. Pedersen, "Wallet Databases with Observers", Springer Berlin Heidelberg, Advances in Cryptology — CRYPTO’ 92 pp. 89-105, DOI 10.1007/3-540-48071-4_7, ISBN ["9783540573401"], , <https://doi.org/10.1007/3-540-48071-4_7>.
[Cheon06]
Cheon, J., "Security Analysis of the Strong Diffie-Hellman Problem", Springer Berlin Heidelberg, Advances in Cryptology - EUROCRYPT 2006 pp. 1-11, DOI 10.1007/11761679_1, ISBN ["9783540345466", "9783540345473"], , <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", Privacy Enhancing Technologies Symposium Advisory Board, Proceedings on Privacy Enhancing Technologies vol. 2018, no. 3, pp. 164-180, DOI 10.1515/popets-2018-0026, , <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", Springer Berlin Heidelberg, Advances in Cryptology — CRYPTO’ 86 pp. 186-194, DOI 10.1007/3-540-47721-7_12, ISBN ["9783540180470"], , <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", Springer Berlin Heidelberg, Lecture Notes in Computer Science pp. 233-253, DOI 10.1007/978-3-662-45608-8_13, ISBN ["9783662456071", "9783662456088"], , <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)", IEEE, 2016 IEEE European Symposium on Security and Privacy (EuroS&P), DOI 10.1109/eurosp.2016.30, , <https://doi.org/10.1109/eurosp.2016.30>.
[NISTCurves]
"Digital Signature Standard (DSS)", National Institute of Standards and Technology, DOI 10.6028/nist.fips.186-4, , <https://doi.org/10.6028/nist.fips.186-4>.
[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-12, , <https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-opaque-12>.
[PrivacyPass]
"Privacy Pass", <https://github.com/privacypass/team>.
[PRIVACYPASS]
Celi, S., Davidson, A., Valdez, S., and C. A. Wood, "Privacy Pass Issuance Protocol", Work in Progress, Internet-Draft, draft-ietf-privacypass-protocol-16, , <https://datatracker.ietf.org/doc/html/draft-ietf-privacypass-protocol-16>.
[RFC7748]
Langley, A., Hamburg, M., and S. Turner, "Elliptic Curves for Security", RFC 7748, DOI 10.17487/RFC7748, , <https://www.rfc-editor.org/rfc/rfc7748>.
[SEC1]
Standards for Efficient Cryptography Group (SECG), "SEC 1: Elliptic Curve Cryptography", <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", In 2017 IEEE 37th International Conference on Distributed Computing Systems (ICDCS), DOI 10.1109/ICDCS.2017.64, , <https://doi.org/10.1109/ICDCS.2017.64>.
[TCRSTW21]
Tyagi, N., Celi, S., Ristenpart, T., Sullivan, N., Tessaro, S., and C. Wood, "A Fast and Simple Partially Oblivious PRF, with Applications", Springer International Publishing, Advances in Cryptology – EUROCRYPT 2022 pp. 674-705, DOI 10.1007/978-3-031-07085-3_23, ISBN ["9783031070846", "9783031070853"], , <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 run the OPRF, VOPRF, and POPRF modes. Each test vector lists the batch size for the evaluation. Each test vector value is encoded as a hexadecimal byte string. The fields of each test vector are described below.

Test vectors with batch size B > 1 have inputs separated by a comma ",". Applicable test vectors will have B different values for the "Input", "Blind", "BlindedElement", "EvaluationElement", and "Output" fields.

The server key material, pkSm and skSm, are listed under the mode for each ciphersuite. Both pkSm and skSm are the serialized values of pkS and skS, respectively, as used in the protocol. Each key pair is derived from a seed Seed and info string KeyInfo, which are listed as well, using the DeriveKeyPair function from 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
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = 06f21f0494f54fc7a4078b133a2d3ebef9e49f398751b5e4c5a3a3a42e15c
1839adce6745c69e8d85496fde14789a866b11358d24b38f017
A.2.1.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = e0ae01c4095f08e03b19baf47ffdc19cb7d98e583160522a3c7
d6a0b2111cd93a126a46b7b41b730cd7fc943d4e28e590ed33ae475885f6c
EvaluationElement = f21783377c064d243a4812b653ea2499804b251843675169
8f26c9908e436163a8fb750db075b9292fce21338498a0f294f3511e118ed5be
Output = adc0e36d6353efedca1300f8b6311b94df98ba855fab56131cefe7c4133
d8d4865b502251f4a1438f9c38b35d96b503ecd58bcfceb19f3d8ebdca691e39c0e9
a
A.2.1.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = 86a88dc5c6331ecfcb1d9aacb50a68213803c462e377577cacc
00af28e15f0ddbc2e3d716f2f39ef95f3ec1314a2c64d940a9f295d8f13bb
EvaluationElement = b28e318772dcbe887f03ccfccfebc331951a03c6e7f7153e
8036cec7ce1e3d87cceb6cfc953b7ecf48241d710b086cdc8603edabe9b0808a
Output = dd0bb8f325fe2b1bb6d4cc3a89f5ea2ddac37fb5a8b9365c0c1d2ac6f0a
ab69504aba3d223f4cd8b78b6d297a9d8167ebdedc0ffd1704241e5c9f1c2a1c1731
f

A.2.2. VOPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = 88067129e7576c0dbd5d868cf5e189dd958fa4760551d8ea15c2fdabff218
9c43f730e71e543b537ccec0bd1497173b021ec6207c37ac930
pkSm = 7ac6049351075957923f00d5bd36c5299ee0b0724c53018c5d01ea239505e
63a4c76f77cb77cf1567fdcdeb5f720118f3b82c9dbfbbb659d
A.2.2.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = 7261bbc335c664ba788f1b1a1a4cd5190cc30e787ef277665ac
1d314f8861e3ec11854ce3ddd42035d9e0f5cddde324c332d8c880abc00eb
EvaluationElement = b65b0074cb65cebbfe64a2ee018321742d1512fd6c14509b
6060c8db3143749bbed9d1896617759ec7c6ebfab032cf2b5eff5f5f5f46796c
Proof = 3fd2c796e71873b9228ccb99c29baff392fda1a8b4711e4b75dab740ef05
d748317e7a136bd5daeaa78b7b3923ddbd67a4d9a7ea3da92836583217ac88426535
5ec9f45326f34178db77dac821f535e941fd8f8c50c06740a6cf04d0e49c50d1cbac
cfd01c1e140a33193b832386410c
ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
Output = dda56f0f50047483cb9a1db473ea9c3aab15d46d99526c091e3141299fc
de4fdd0ce3bf654542687b90fe01aab2fdf06d523317122a24beea800893583735b1
e
A.2.2.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = 88287e553939090b888ddc15913e1807dc4757215555e1c3a79
488ef311594729c7fa74c772a732b78440b7d66d0aa35f3bb316f1d93e1b2
EvaluationElement = 088947cd184cdaff715fb47130758238ecc1f05e049dbbd9
2cfef18a87e39e66728c79834f3fec33c96a57d34ed5c399e5e8c689331393ee
Proof = 3771a89bfd4540c023db27251d5173640006d1ca76d4d7ad0a2236c2ee07
3dad7863e2d88414b9bd9c0b9fa1c61620e66bdefd304a2c120fbc959de3d8188a88
c0da281b1df1dbd2f4edb3c019363629bd2c8d5b5408792a1dabb985597e5905a9a2
2fcd55c5b3b34c20ce81ee91560b
ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
Output = fafbc029fef15f19545e5d1114275b21aab79bad25d7fff2fe1db99835e
706afde10b76a6766e61ac4064a9cb559d9afcede5a06cbc0178554608b13f9f751b
0
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 = b65b0074cb65cebbfe64a2ee018321742d1512fd6c14509b
6060c8db3143749bbed9d1896617759ec7c6ebfab032cf2b5eff5f5f5f46796c,b43
1aac4e9a620bd04e77f90ca3eeca7d69fd6c48c3d470a4bd4481cd2e81653e9df277
74d94cfd39fdce73156da2d130ef8c025587d0fd2
Proof = 59451d30e29ebb47e72e674f0ac2aff39d2c9c274f15f9f40930c11d6c71
363c6a986e4ac3703bb450838414824512d2dac01088d5574718a6011ed95b40c77b
3054290e9fc6044fe4eec801ed2f6f97aba5a87b2b4ac5f4060405f6baf91d785e35
87357571223894a934fa31a94a2f
ProofRandomScalar = 63798726803c9451ba405f00ef3acb633ddf0c420574a2ec
6cbf28f840800e355c9fbaac10699686de2724ed22e797a00f3bd93d105a7f23
Output = dda56f0f50047483cb9a1db473ea9c3aab15d46d99526c091e3141299fc
de4fdd0ce3bf654542687b90fe01aab2fdf06d523317122a24beea800893583735b1
e,fafbc029fef15f19545e5d1114275b21aab79bad25d7fff2fe1db99835e706afde
10b76a6766e61ac4064a9cb559d9afcede5a06cbc0178554608b13f9f751b0

A.2.3. POPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = 3d4cd3c711a8ff4642aefcd9972c4a72d261188814286a483815a77e444a2
fb561f1748852f33a2f3bf7d86b0e27bf9fecad341bf286b116
pkSm = 2094323c2495a91d411d8967759cbcd694aef26ea0b5005e9e29a07d19452
b3b9b31d4ee14c51caa47f910e0553e402b050bf32011543c98
A.2.3.1. Test Vector 1, Batch Size 1
Input = 00
Info = 7465737420696e666f
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = 161183c13c6cb33b0e4f9b7365f8c5c12d13c72f8b62d276ca0
9368d093dce9b42198276b9e9d870ac392dda53efd28d1b7e6e8c060cdc42
EvaluationElement = 54ea555d854bfcfe1c36cdf7739a0442a94a90ee2a9369f4
d59f27e51535809bf78f899365c9d6e723a6ea49628c553f6123564eb0d0605b
Proof = be0ecfd970cacf75cf9f34ad5f5c2f6857c017048b8fe013b948b1139efb
e68e10412fd01f174c9761964b9061e25220fa79dccfc7031b1239a1f21d6a5ddd49
757c535a26c4b6dfcfeef06cf3a60a7504c89eae4645187c0a7b81fd5d88fa32693c
61b58b22ab9bc80f53f16f592602
ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
Output = 52cee2e34fe3ae382e1dea686c8de69f04a4d9ecb87b96fb03629e40c4f
343a4e7a30a614a674bf8414f47bf57974efd4edcf507eb0d5828b117a9e04f717cc
f
A.2.3.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Info = 7465737420696e666f
Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa
3833a26e9388336361686ff1f83df55046504dfecad8549ba112
BlindedElement = 12082b6a381c6c51e85d00f2a3d828cdeab3f5cb19a10b9c014
c33826764ab7e7cfb8b4ff6f411bddb2d64e62a472af1cd816e5b712790c6
EvaluationElement = f894d02299d051a78ff671acf77acc0f8aa1b5fa2c6f46b7
2348ee3b6ede9e9522a42722dfd67e5db5aa8a65caa0e75f6107c576cf015c4d
Proof = 3e1ee8d20471a6127c6c7fffa7c3fc505b3cee4762ed2c5cdafaf56a59ea
e5283510da6eeffdcfe960dd7b5830ce5af1594d6ede1bcc6921ef098970280a0ef1
4196668522c67c8d0f05f5baa0b9984c2aad1f16362d7fbad0883b08b1f1b36a38dd
fcf9359a35c2bf09fd0042d2b12a
ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0
627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b
Output = 5f750ede71e2b80e45925789c71b33309ff32c01a81d05d4f6b19b13de8
65ea8bcedd6e8d0bf6c6ca8882020fb1d179ec7c4dcc1aaeff0c33e642c9727ba371
2
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 = 54ea555d854bfcfe1c36cdf7739a0442a94a90ee2a9369f4
d59f27e51535809bf78f899365c9d6e723a6ea49628c553f6123564eb0d0605b,2c9
621cdf875fc6a2c6d9efe62a3518b3bd9d0e44a7eab9352a4de94b45b6c103e3a2cf
22d5621a51661f7c19dd6ef5922f25acb2e9bb5e1
Proof = 9d949521a609be7d2c2b31e949dada02ebed264aad825857224180a3c6a9
863515b6044eab07cb6eb9734ec3d4c0448fb0ec49f38c1ac337f1d17eced9071e71
fd58dc4425307c1e9907bc5bb51b8a978689a6eba812e162617accf08d7817c320ec
6354647ad2f9e8f3abf742347724
ProofRandomScalar = 63798726803c9451ba405f00ef3acb633ddf0c420574a2ec
6cbf28f840800e355c9fbaac10699686de2724ed22e797a00f3bd93d105a7f23
Output = 52cee2e34fe3ae382e1dea686c8de69f04a4d9ecb87b96fb03629e40c4f
343a4e7a30a614a674bf8414f47bf57974efd4edcf507eb0d5828b117a9e04f717cc
f,5f750ede71e2b80e45925789c71b33309ff32c01a81d05d4f6b19b13de865ea8bc
edd6e8d0bf6c6ca8882020fb1d179ec7c4dcc1aaeff0c33e642c9727ba3712

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
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = b16c4f85142a577411d0621516c6c48b928363575a9b27dca10e553de74af
0c2096ed9deed1792ee9665dcbcd4bd7c35
A.4.1.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 02a36bc90e6db34096346eaf8b7bc40ee1113582155ad379700
3ce614c835a874343701d3f2debbd80d97cbe45de6e5f1f
EvaluationElement = 033b7c36005ca1d8bb9e18198d6b379c662739bd65f716fc
f3fdb384d61624b96c4ad3911b861ad8b1b24e85acc1613b05
Output = 91961a85dca85527b88ac94c1642c449e944ac463b9d1696bcd2efe6d38
f9cc8a2480f57b45536f3ce8062e8e54f16fb
A.4.1.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 02def6f418e3484f67a124a2ce1bfb19de7a4af568ede6a1ebb
2733882510ddd43d05f2b1ab5187936a55e50a847a8b900
EvaluationElement = 022317c418d5f836d4fcab18b887111a54b5015b54f4fcae
e8b2edc7e79b1c7f24e0a1a8a548874679c8705a547b34447d
Output = aa385f328a0ed4dd9af751f63d27d10a41226ec095a4eec5237071579ac
da69ccbc0d0c8a2ab4d033934e7987f2b10d4

A.4.2. VOPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = afc3a71e59eaa2684d4da6f01f41977471e3efeefb11454168f9fecf384cf
f934332355d631f83d3aec9bd36a940be5a
pkSm = 02139a4c608f418c458409bbc9970796bd784cf5a4251578276d5a005706a
130c75e4d440e463fa3ca9bd56394a00ae470
A.4.2.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 02d338c05cbecb82de13d6700f09cb61190543a7b7e2c6cd4fc
a56887e564ea82653b27fdad383995ea6d02cf26d0e24d9
EvaluationElement = 0202df7145c1fb3cf57fd4bc062d58d06034a1ae63b02b91
ba4f57f57187f98f7cf026b5bc9a4ea1aa6e40b94b8f53a826
Proof = 23e19b916ba705bd55d541dc11af23a99d2754ac46aa9b8158f3274d69b4
75988a377e4ded17a319fbdc2ac1391cb4ac74b59787298ee213976accea1cada09b
aeb5303a1b133fff96a08562864d19751a57144d3477e4c59935222f29c3e728
ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
Output = 5e6261bfb3d397c8f90dfda0782a8450c70013489cffe8f60c205843d55
dd350da52d6fb2e96d9c779e083c5acea67b4
A.4.2.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 02f27469e059886f221be5f2cca03d2bdc61e55221721c3b3e5
6fc012e36d31ae5f8dc058109591556a6dbd3a8c69c433b
EvaluationElement = 0342050f2c95bc49cf48442703bb772335113dd9c54b6280
3b2cfc3a2aed78030a6a27fa088bf491c290c7e905a3a1c781
Proof = 13a5a0ea31ce00a35d5e90cd2d00ff0b830d3f87f23b757fa547a592b7e9
be955528d81852869fec6d2c986a75c09f628bf3ff14d18a5c7a8b4b6bb22dced106
34590314c4415b5f420257694052832977dfaac46bd119e8ef8c3126f3a0d312
ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
Output = 0a3b70080afe17322a0c15411dcb7b9d64ca8a6730174446c2407499c2c
44f2a029ab7a48d1dbebbc4507539c2a2ee35
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 = 0202df7145c1fb3cf57fd4bc062d58d06034a1ae63b02b91
ba4f57f57187f98f7cf026b5bc9a4ea1aa6e40b94b8f53a826,03c4ee254c71a5081
f965280a7db1d5882dbeb1ab5ade0400e7007b730a87cfb07ae5f651572714633ec8
26c52705cb6ec
Proof = d5aeca08e8f2a424606fbec6bd08060310883e639210d1d4a659b0ffce29
7f651d89b542335bc4739204d76cd97d5a7491af9e63418a559f36b5e72fa1867a45
4fae36bf3074d0ad5dff69eb1f6ecd19083a271fa30f87c5e854057d6f98e378
ProofRandomScalar = a097e722ed2427de86966910acba9f5c350e8040f828bf6c
eca27405420cdf3d63cb3aef005f40ba51943c8026877963
Output = 5e6261bfb3d397c8f90dfda0782a8450c70013489cffe8f60c205843d55
dd350da52d6fb2e96d9c779e083c5acea67b4,0a3b70080afe17322a0c15411dcb7b
9d64ca8a6730174446c2407499c2c44f2a029ab7a48d1dbebbc4507539c2a2ee35

A.4.3. POPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3
KeyInfo = 74657374206b6579
skSm = 79f09d6067bc438dcecf3299af6c38f0045681a28658a73162a5c6f1700aa
aca21c27b9711d84e38b56fd81710488a5e
pkSm = 023d5a2f4cf07f823e317a852935d59f4d1e426ed41d87eab1734d660818a
fe5ede9713836d16e31edcb55ecbad35f3c9e
A.4.3.1. Test Vector 1, Batch Size 1
Input = 00
Info = 7465737420696e666f
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 03859b36b95e6564faa85cd3801175eda2949707f6aa0640ad0
93cbf8ad2f58e762f08b56b2a1b42a64953aaf49cbf1ae3
EvaluationElement = 0350c1f39f77834618ff2f98b00ad184f65e83c5f04b469b
4f042b62c9c46cd9e50dfc946f5ee9a2a53c86824197d42dc4
Proof = cd845a3c6329e3d1f5c9e6a2985c613fc1f71168589eac679387bed21814
1aa2e1b92692ff3224eb30f4f17569a53ae0f302f0218cece17ac09b58663685847b
df719c073ad97f0fbee5acb53c175ece3c96dad6d7b926a4c2439d9a9ced9d45
ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
Output = 6a7b0005c9a93a50b0e8e5b70d5a903610731ca1e6dc912ed18c2c7e840
e9b4fd0734e3f070936d9b816132c9eafaa62
A.4.3.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Info = 7465737420696e666f
Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562
889d89dbfa691d1cde91517fa222ed7ad364
BlindedElement = 03f7efcb4aaf000263369d8a0621cb96b81b3206e99876de2a0
0699ed4c45acf3969cd6e2319215395955d3f8d8cc1c712
EvaluationElement = 02050d70ca554bde7caadbcbc94282ffdf99ae7a86097a88
2c585222d200cb08644fa63500dbe75e41027c36bb4eb902ae
Proof = 6900d5f3c87c4cb64d976130ba4530153de4be61975f4151baea07b1f9bf
49b420b1639be9a96d68a40a42da4cf3da594449ba20a1868b9626a39ca9cd6ee609
5a7435f1b0bfd83dc4baa15f375bf0bed3e7974a05d87bc4040a608bd6ad7216
ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62
c095021db018cd8cbb55941d4073698ce45c405d1348b7b1
Output = fcc8d222669da6b61090d961a2c6cce490f0f798d72b6b1abbe9c12a087
45f41b43c29cdca294ddc72d1e207360cffe4
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 = 0350c1f39f77834618ff2f98b00ad184f65e83c5f04b469b
4f042b62c9c46cd9e50dfc946f5ee9a2a53c86824197d42dc4,03c55d2575fce00cd
49069be4e562af213a39f32e56fd4eaabc67e5a6cba01a7121ce7f99849023a9ee88
e9aa8b5751651
Proof = 90b15a1b120b904deac1cdafda3dfef14764a74397d99e63c0f9e0694ee0
17b1d3bce7c465cf663b3a958e6cca8fd276ae7ee5f1a754e4dbcc6cc6ffedb154a2
0e2fa7b3535d1a2cde60137a386c46465431d64edc311e2970ff7b1511e68d4b
ProofRandomScalar = a097e722ed2427de86966910acba9f5c350e8040f828bf6c
eca27405420cdf3d63cb3aef005f40ba51943c8026877963
Output = 6a7b0005c9a93a50b0e8e5b70d5a903610731ca1e6dc912ed18c2c7e840
e9b4fd0734e3f070936d9b816132c9eafaa62,fcc8d222669da6b61090d961a2c6cc
e490f0f798d72b6b1abbe9c12a08745f41b43c29cdca294ddc72d1e207360cffe4

A.5. P521-SHA512

A.5.1. OPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3
KeyInfo = 74657374206b6579
skSm = 00df1c651aa393bcd50c7ecf06f8472706dcb2c41ceadca770569d10be389
0f7102a720e36fc7b84fca500d76715b9356f7b4bdca20aff5ef4cd7bb344b0b2c01
d98
A.5.1.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 0300e78bf846b0e1e1a3c320e353d758583cd876df56100a3a1
e62bacba470fa6e0991be1be80b721c50c5fd0c672ba764457acc18c6200704e9294
fbf28859d916351
EvaluationElement = 0301d6fdc5bdc3434afce77ff15072fcd99b83e608718bac
4d05539e7e2bae12dd5475a0de4938eb3be5c1bf37f0b2c99daa9ab84cadbf068d7b
18a5fca8de7a99790e
Output = e18fc074d9c79168e9ce9f386969a8a999087b2b84136c952ffac454674
f92475cb78b33fe347762924bfaae7182bb9a8a043a157c862d1d93ca12ff16ad205
5
A.5.1.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 0300c28e57e74361d87e0c1874e5f7cc1cc796d61f9cad50427
cf54655cdb455613368d42b27f94bf66f59f53c816db3e95e68e1b113443d66a99b3
693bab88afb556b
EvaluationElement = 0301bea09ae35a633a769a3af78f491325e7d66ed0939774
df74faab4e50e344031a9ec28d8ccf95997b8a300a42bee00539bfc07c3355904278
57d2fc6e2e5d1c0b8b
Output = 07c31b9b01c59b3d8367ba70e521103a3b41e544613c372b445b55e4012
4093e060b48a15c7dfbee5f00e147e180a676fc1e3343453175f7ed22ba99a1f96a2
d

A.5.2. VOPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3
KeyInfo = 74657374206b6579
skSm = 015cc2356215d2d35d84f0ade8633d8da044db46b5e7eee56b60b956e9f68
4a8a751fbf7de3d17fa9567c93b8c951030ec23ca1e4b88c0686a941d2cf809081c5
86a
pkSm = 0301b9339969103060f1761f4b439a88b71ba0c28a95cc12dbe051cbeffaa
adc1305edbf11e0b8927a59fa2cd436f1a780d0d4586966d5964195fcee03d28b64b
fec5c
A.5.2.1. Test Vector 1, Batch Size 1
Input = 00
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 0301d6e4fb545e043ddb6aee5d5ceeee1b44102615ab04430c2
7dd0f56988dedcb1df32ef384f160e0e76e718605f14f3f582f9357553d153b99679
5b4b3628a4f6380
EvaluationElement = 0300397942f9cb70ba07d8c2f13c5d89d28dd555ee24111b
2fbefe0669c3f1dfaab36a650178b8d8aa80cba37154002085c8ca41b769645a5b92
ab177231b7adad246d
Proof = 001d875491db0ff0dd080c000bf5d9b4e97febb68e1700847da591da5c6a
5691987e07d111d578fe83b7deaed73800f376a391b278353ea3985033347ecf5866
c5a201794d493edbc971c7f3700d56cf093f1f8b1bd4767423bfdd3474092b9abf60
b2341b17c4e82c85f28702be03d172e60e66213a8e607516f576be20d2ebcf574cce
ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
e45c405d1348b7b1
Output = 0bf9f06d0b9dbbe112b7c448fc8e50e89a0c24034cd8eae61053ccf7d26
0f7bfe89e923cc393f3b61d9b8aa6640507c64f4b7254d03834596c45660cdc3a8ad
4
A.5.2.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 03005b05e656cb609ce5ff5faf063bb746d662d67bbd07c0626
38396f52f0392180cf2365cabb0ece8e19048961d35eeae5d5fa872328dce98df076
ee154dd191c615e
EvaluationElement = 02008383895def4559191da26c3dd79fdf374ac6ff3c8f67
b58bbf9e1d155c4af557fb8b3ee3efefb5b904c38dc04bf026ae48b8e6e658350724
66adef43f14b1fa111
Proof = 01e6264d0c12af0c856930c71750893cf7c7f018642b53974b827e263a88
5614e612934a83ad81647c77813857745ef57693359a83e6ece547e3fad97df0f195
66c00045a989202905671fb44bcc54399b03b19cbd2912755627d0f29fc5ce7ee684
9c0b159ed1010393796dff4697c2be5ebcdbc70e0c54d489ebbd9f87306eaaf42d2d
ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
e45c405d1348b7b1
Output = c3e58e1c8c5677f64cf36efd4f94fd4e29a297f62db161cb2dbb8388b8b
4536fcd8696eb1474da382e3ab8eea9e8d659186314658a352fab40e80cf4d2663db
3
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 = 0300397942f9cb70ba07d8c2f13c5d89d28dd555ee24111b
2fbefe0669c3f1dfaab36a650178b8d8aa80cba37154002085c8ca41b769645a5b92
ab177231b7adad246d,0301a2ea923601bdacd247156627e341995a484a445434d32
da913e71ca2d36d094a34ea02306d3465b45f5a292196db531618348a874b7d58f5d
d3e67fb2c0f5dfaf5
Proof = 0054b2e651d10311cf74226d4b9cb283f1ae6bbde586e3e2621b20d935a2
0d9d73773a13bd8539a75dffa7124e94aca6b588fc7d2cf5edaac07af996ddf1a50b
829a003ff316174d7e84b123af2476332842133339a464e833a69b8bc4c8ecb2332a
0f828752787892423753caf5d415c649195f756ad52bdc94ea196775b21d192627d8
ProofRandomScalar = 01ec21c7bb69b0734cb48dfd68433dd93b0fa097e722ed24
27de86966910acba9f5c350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
51943c8026877963
Output = 0bf9f06d0b9dbbe112b7c448fc8e50e89a0c24034cd8eae61053ccf7d26
0f7bfe89e923cc393f3b61d9b8aa6640507c64f4b7254d03834596c45660cdc3a8ad
4,c3e58e1c8c5677f64cf36efd4f94fd4e29a297f62db161cb2dbb8388b8b4536fcd
8696eb1474da382e3ab8eea9e8d659186314658a352fab40e80cf4d2663db3

A.5.3. POPRF Mode

Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a
3a3
KeyInfo = 74657374206b6579
skSm = 01f494b76f11776ffc15f6b5613110e7db8e4a6a87721714c1e86289c192b
1ec97d358eb0e2c445c2475f775e7b389ae35c5001ce337ae65ef5c67c7b22ca3d90
ce0
pkSm = 0300cb19d7aadaf3f2819ceba73a41e998eb5103b2d95e4d077b3c3b5a848
e9a8e782a259066a43b9fc3503d9a38c79ccd59df77bed87cc5d312bb42cbe381d01
27d3d
A.5.3.1. Test Vector 1, Batch Size 1
Input = 00
Info = 7465737420696e666f
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 020095cff9d7ecf65bdfee4ea92d6e748d60b02de34ad98094f
82e25d33a8bf50138ccc2cc633556f1a97d7ea9438cbb394df612f041c485a515849
d5ebb2238f2f0e2
EvaluationElement = 0200c263a592b15ac199c6a2774aad95f755f921478b7e1a
cbe93dac76f08e66c04b92715d187a453c9860aa542801ce86ca01c0a1292afb5ed4
43e21b26a7a0d94f8e
Proof = 01574b60ace43c26421cadd5bb964b68d24e08cb5bc87aa84d16dee6cdc6
c3ef6df301df2c742f17de2e37fdffd84fe5b8abd86f10a0a35e149490a85eb2f31a
072800186a683eacbf7a72d7586b0f86b8bab0b808eeb7ccf0d2f244bbec2a588179
8fcd6dfd9f7500a7cee48620d58472b973a5aad9f4180fae3340b30ff831cc12bdc4
ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
e45c405d1348b7b1
Output = 062781972249cc88fc2d8776ab44d549d3b0bd1f448ae4f92ef86e26a2b
48c4e0915b8f2906dbe9eb768745eb756cc455a0e304185f6e199e726e9a68e3a7cc
2
A.5.3.2. Test Vector 2, Batch Size 1
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a
Info = 7465737420696e666f
Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333
88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a
d364
BlindedElement = 030112ea89cf9cf589496189eafc5f9eb13c9f9e170d6ecde7c
5b940541cb1a9c5cfeec908b67efe16b81ca00d0ce216e34b3d5f46a658d3fd8573d
671bdb6515ed508
EvaluationElement = 0200aee0d2a2dbe1d7f7fbd631097b88079ec75e73660366
85551225985a3c11de66d5fb849d43f5ae64275a0d97fc9934022e0d294745554816
7dbfcca35a77492b1e
Proof = 01255bbcd02f6aec5a784e369c2956497c63b8708cc5ac05168ed5fab1be
8ee5733abe0f82ac90470961b33e49b20667191d7438d0f39af3048f29417e1ceb61
b99501dee51fd130b9089bde60f68c92d57ed56832a07508ccd6aecac7cee5e3be5a
eb630e262cc3fd071d97d79657456c813a80c11ef60d734aa368de22d01fde7b95ae
ProofRandomScalar = 015e80ae32363b32cb76ad4b95a5a34e46bb803d955f0e07
3a04aa5d92b3fb739f56f9db001266677f62c095021db018cd8cbb55941d4073698c
e45c405d1348b7b1
Output = d99d9fa0b23ccb3f92a509c48ea2ecef5d6622c6f780a46729162b2a16f
4112b2ab863a3b3e1235ae2926b8ab090d3edcfbfacec450522dd73ff0492194db7c
4
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 = 0200c263a592b15ac199c6a2774aad95f755f921478b7e1a
cbe93dac76f08e66c04b92715d187a453c9860aa542801ce86ca01c0a1292afb5ed4
43e21b26a7a0d94f8e,0201b4f20e1594fdaa956a84d14f44241569f96b15b598f14
3826143da75124d2875c19d5836f3971bcaf74ccb84243bbc8fcaf72eaaca0753e22
756529a7c1d3b383b
Proof = 00098c47430440e6687696a4bd397653fc9f6f13084866059a7ad8729daa
9f0895a30cc21c958d6e595d1bfad449fa70d54f97fb23c6b2aa13a8135fe97b7c84
b58401b7a23f62ba35c49345757722e50090d59fd1a278c97d5fa588bf501d562978
65e0f53330bf5429499b667a44889c8f864e7f367689e395172d1535fb5f5be1a68a
ProofRandomScalar = 01ec21c7bb69b0734cb48dfd68433dd93b0fa097e722ed24
27de86966910acba9f5c350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba
51943c8026877963
Output = 062781972249cc88fc2d8776ab44d549d3b0bd1f448ae4f92ef86e26a2b
48c4e0915b8f2906dbe9eb768745eb756cc455a0e304185f6e199e726e9a68e3a7cc
2,d99d9fa0b23ccb3f92a509c48ea2ecef5d6622c6f780a46729162b2a16f4112b2a
b863a3b3e1235ae2926b8ab090d3edcfbfacec450522dd73ff0492194db7c4

Authors' Addresses

Alex Davidson
Brave Software
Armando Faz-Hernandez
Cloudflare, Inc.
101 Townsend St
San Francisco,
United States of America
Nick Sullivan
Cloudflare, Inc.
101 Townsend St
San Francisco,
United States of America
Christopher A. Wood
Cloudflare, Inc.
101 Townsend St
San Francisco,
United States of America