Internet-Draft | OPRFs | October 2023 |
Davidson, et al. | Expires 12 April 2024 | [Page] |
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.¶
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.¶
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.¶
Copyright (c) 2023 IETF Trust and the persons identified as the document authors. All rights reserved.¶
This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document. Code Components extracted from this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions and are provided without warranty as described in the Revised BSD License.¶
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.¶
Apply more IRSG review comments.¶
Address IRSG comments.¶
Fix error.¶
Apply editorial suggestions from CFRG chair review.¶
Change how suites are identified and finalize test vectors.¶
Apply editorial suggestions from IRTF chair review.¶
Apply editorial suggestions from document shepherd.¶
Apply editorial suggestions from CFRG RGLC.¶
Correct current state of formal analysis for the VOPRF protocol variant.¶
Editorial improvements based on Crypto Panel Review.¶
Small editorial fixes¶
Change Evaluate to BlindEvaluate, and add Evaluate for PRF evaluation¶
Editorial improvements¶
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.¶
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.¶
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.¶
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.¶
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.¶
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.¶
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.¶
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.¶
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.¶
The protocols in this document have two primary dependencies:¶
Group
: A prime-order group implementing the API described below in Section 2.1.
See Section 4 for specific instances of groups.¶
Hash
: A cryptographic hash function whose output length is Nh
bytes.¶
Section 4 specifies ciphersuites as combinations of Group
and Hash
.¶
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.¶
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.¶
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.¶
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.¶
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.¶
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.¶
The POPRF mode extends the VOPRF mode such that the client and
server can additionally provide a public input info
that is used in computing
the pseudorandom function. That is, the client and server interact to compute
output = F(skS, input, info)
as is shown below.¶
Each protocol consists of an offline setup phase and an online phase, described in Section 3.2 and Section 3.3, respectively. Configuration details for the offline phase are described in Section 3.1.¶
Each of the three protocol variants are identified with a one-byte value (in hexadecimal):¶
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¶
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)¶
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¶
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.¶
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)¶
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.¶
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)¶
A ciphersuite (also referred to as 'suite' in this document) for the protocol wraps the functionality required for the protocol to take place. The ciphersuite should be available to both the client and server, and agreement on the specific instantiation is assumed throughout.¶
A ciphersuite contains instantiations of the following functionalities:¶
Group
: A prime-order Group exposing the API detailed in Section 2.1, with the
generator element defined in the corresponding reference for each group. Each
group also specifies HashToGroup, HashToScalar, and serialization
functionalities. For
HashToGroup, the domain separation tag (DST) is constructed in accordance
with the recommendations in [I-D.irtf-cfrg-hash-to-curve], Section 3.1.
For HashToScalar, each group specifies an integer order that is used in
reducing integer values to a member of the corresponding scalar field.¶
Hash
: A cryptographic hash function whose output length is Nh bytes long.¶
This section includes an initial set of ciphersuites with supported groups and hash functions. It also includes implementation details for each ciphersuite, focusing on input validation. Future documents can specify additional ciphersuites as needed provided they meet the requirements in Section 4.6.¶
For each ciphersuite, contextString
is that which is computed in the Setup functions.
Applications should take caution in using ciphersuites targeting P-256 and ristretto255.
See Section 7.2 for related discussion.¶
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])¶
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.¶
This ciphersuite uses decaf448 [RISTRETTO] for the Group and SHAKE-256 for the Hash function. The value of the ciphersuite identifier is "decaf448-SHAKE256".¶
Order(): Return 2^446 - 13818066809895115352007386748515426880336692474882178609894547503885¶
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.¶
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.¶
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.¶
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.¶
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.¶
Two popular algorithms for generating a random integer uniformly distributed in the range [0, G.Order() -1] are as follows:¶
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.¶
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
.¶
This section describes considerations for applications, including external interface recommendations, explicit error treatment, and public input representation for the POPRF protocol variant.¶
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.¶
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.¶
Some OPRF variants specified in this document have fallible operations. For example, Finalize
and BlindEvaluate
can fail if any element received from the peer fails input validation.
The explicit errors generated throughout this specification, along with the
conditions that lead to each error, are as follows:¶
VerifyError
: Verifiable OPRF proof verification failed; Section 3.3.2 and Section 3.3.3.¶
DeserializeError
: Group Element or Scalar deserialization failure; Section 2.1 and Section 3.3.¶
InputValidationError
: Validation of byte array inputs failed; Section 4.¶
There are other explicit errors generated in this specification; however, they occur with negligible probability in practice. We note them here for completeness.¶
InvalidInputError
: OPRF Blind input produces an invalid output element; Section 3.3.1 and Section 3.3.3.¶
InverseError
: A tweaked private key is invalid (has no multiplicative inverse); Section 2.1 and Section 3.3.¶
In general, the errors in this document are meant as a guide to implementors. They are not an exhaustive list of all the errors an implementation might emit. For example, implementations might run out of memory and return a corresponding error.¶
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.¶
This document has no IANA actions.¶
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.¶
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.¶
Below, we discuss the cryptographic security of each protocol variant from Section 3, relative to the necessary cryptographic assumptions that need to be made.¶
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:¶
This document does not use session identifiers to differentiate different instances of the protocol; and¶
This document supports batching so that multiple evaluations can happen at once whilst only constructing one DLEQ proof object. This is enabled using an established batching technique [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.¶
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.)¶
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).¶
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.¶
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
.¶
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.¶
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.¶
"Input": The private client input, an opaque byte string.¶
"Info": The public info, an opaque byte string. Only present for POPRF test vectors.¶
"Blind": The blind value output by Blind()
, a serialized Scalar
of Ns
bytes long.¶
"BlindedElement": The blinded value output by Blind()
, a serialized
Element
of Ne
bytes long.¶
"EvaluatedElement": The evaluated element output by BlindEvaluate()
,
a serialized Element
of Ne
bytes long.¶
"Proof": The serialized Proof
output from GenerateProof()
composed of
two serialized Scalar
values each of Ns
bytes long. Only present for
VOPRF and POPRF test vectors.¶
"ProofRandomScalar": The random scalar r
computed in GenerateProof()
, a
serialized Scalar
of Ns
bytes long. Only present for VOPRF and POPRF
test vectors.¶
"Output": The protocol output, an opaque byte string of length Nh
bytes.¶
Test vectors with batch size B > 1 have inputs separated by a comma ",". Applicable test vectors will have B different values for the "Input", "Blind", "BlindedElement", "EvaluationElement", and "Output" fields.¶
The server key material, pkSm
and skSm
, are listed under the mode for
each ciphersuite. Both pkSm
and skSm
are the serialized values of
pkS
and skS
, respectively, as used in the protocol. Each key pair
is derived from a seed Seed
and info string KeyInfo
, which are
listed as well, using the DeriveKeyPair
function from Section 3.2.¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 5ebcea5ee37023ccb9fc2d2019f9d7737be85591ae8652ffa9ef0f4d37063 b0e¶
Input = 00 Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = 609a0ae68c15a3cf6903766461307e5c8bb2f95e7e6550e1ffa 2dc99e412803c EvaluationElement = 7ec6578ae5120958eb2db1745758ff379e77cb64fe77b0b2 d8cc917ea0869c7e Output = 527759c3d9366f277d8c6020418d96bb393ba2afb20ff90df23fb770826 4e2f3ab9135e3bd69955851de4b1f9fe8a0973396719b7912ba9ee8aa7d0b5e24bcf 6¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = da27ef466870f5f15296299850aa088629945a17d1f5b7f5ff0 43f76b3c06418 EvaluationElement = b4cbf5a4f1eeda5a63ce7b77c7d23f461db3fcab0dd28e4e 17cecb5c90d02c25 Output = f4a74c9c592497375e796aa837e907b1a045d34306a749db9f34221f7e7 50cb4f2a6413a6bf6fa5e19ba6348eb673934a722a7ede2e7621306d18951e7cf2c7 3¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = e6f73f344b79b379f1a0dd37e07ff62e38d9f71345ce62ae3a9bc60b04ccd 909 pkSm = c803e2cc6b05fc15064549b5920659ca4a77b2cca6f04f6b357009335476a d4e¶
Input = 00 Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = 863f330cc1a1259ed5a5998a23acfd37fb4351a793a5b3c090b 642ddc439b945 EvaluationElement = aa8fa048764d5623868679402ff6108d2521884fa138cd7f 9c7669a9a014267e Proof = ddef93772692e535d1a53903db24367355cc2cc78de93b3be5a8ffcc6985 dd066d4346421d17bf5117a2a1ff0fcb2a759f58a539dfbe857a40bce4cf49ec600d ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98 81aa6f61d645fc0e Output = b58cfbe118e0cb94d79b5fd6a6dafb98764dff49c14e1770b566e42402d a1a7da4d8527693914139caee5bd03903af43a491351d23b430948dd50cde10d32b3 c¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = cc0b2a350101881d8a4cba4c80241d74fb7dcbfde4a61fde2f9 1443c2bf9ef0c EvaluationElement = 60a59a57208d48aca71e9e850d22674b611f752bed48b36f 7a91b372bd7ad468 Proof = 401a0da6264f8cf45bb2f5264bc31e109155600babb3cd4e5af7d181a2c9 dc0a67154fabf031fd936051dec80b0b6ae29c9503493dde7393b722eafdf5a50b02 ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98 81aa6f61d645fc0e Output = 8a9a2f3c7f085b65933594309041fc1898d42d0858e59f90814ae90571a 6df60356f4610bf816f27afdd84f47719e480906d27ecd994985890e5f539e7ea74b 6¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 145c79c108538421ac164ecbe131942136d5570b16d8bf41a24d4337da981 e07 pkSm = c647bef38497bc6ec077c22af65b696efa43bff3b4a1975a3e8e0a1c5a79d 631¶
Input = 00 Info = 7465737420696e666f Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = c8713aa89241d6989ac142f22dba30596db635c772cbf25021f dd8f3d461f715 EvaluationElement = 1a4b860d808ff19624731e67b5eff20ceb2df3c3c03b906f 5693e2078450d874 Proof = 41ad1a291aa02c80b0915fbfbb0c0afa15a57e2970067a602ddb9e8fd6b7 100de32e1ecff943a36f0b10e3dae6bd266cdeb8adf825d86ef27dbc6c0e30c52206 ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98 81aa6f61d645fc0e Output = ca688351e88afb1d841fde4401c79efebb2eb75e7998fa9737bd5a82a15 2406d38bd29f680504e54fd4587eddcf2f37a2617ac2fbd2993f7bdf45442ace7d22 1¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Info = 7465737420696e666f Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec4c1f 6706 BlindedElement = f0f0b209dd4d5f1844dac679acc7761b91a2e704879656cb7c2 01e82a99ab07d EvaluationElement = 8c3c9d064c334c6991e99f286ea2301d1bde170b54003fb9 c44c6d7bd6fc1540 Proof = 4c39992d55ffba38232cdac88fe583af8a85441fefd7d1d4a8d0394cd1de 77018bf135c174f20281b3341ab1f453fe72b0293a7398703384bed822bfdeec8908 ProofRandomScalar = 222a5e897cf59db8145db8d16e597e8facb80ae7d4e26d98 81aa6f61d645fc0e Output = 7c6557b276a137922a0bcfc2aa2b35dd78322bd500235eb6d6b6f91bc5b 56a52de2d65612d503236b321f5d0bebcbc52b64b92e426f29c9b8b69f52de98ae50 7¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = 06f21f0494f54fc7a4078b133a2d3ebef9e49f398751b5e4c5a3a3a42e15c 1839adce6745c69e8d85496fde14789a866b11358d24b38f017¶
Input = 00 Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa 3833a26e9388336361686ff1f83df55046504dfecad8549ba112 BlindedElement = e0ae01c4095f08e03b19baf47ffdc19cb7d98e583160522a3c7 d6a0b2111cd93a126a46b7b41b730cd7fc943d4e28e590ed33ae475885f6c EvaluationElement = f21783377c064d243a4812b653ea2499804b251843675169 8f26c9908e436163a8fb750db075b9292fce21338498a0f294f3511e118ed5be Output = adc0e36d6353efedca1300f8b6311b94df98ba855fab56131cefe7c4133 d8d4865b502251f4a1438f9c38b35d96b503ecd58bcfceb19f3d8ebdca691e39c0e9 a¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa 3833a26e9388336361686ff1f83df55046504dfecad8549ba112 BlindedElement = 86a88dc5c6331ecfcb1d9aacb50a68213803c462e377577cacc 00af28e15f0ddbc2e3d716f2f39ef95f3ec1314a2c64d940a9f295d8f13bb EvaluationElement = b28e318772dcbe887f03ccfccfebc331951a03c6e7f7153e 8036cec7ce1e3d87cceb6cfc953b7ecf48241d710b086cdc8603edabe9b0808a Output = dd0bb8f325fe2b1bb6d4cc3a89f5ea2ddac37fb5a8b9365c0c1d2ac6f0a ab69504aba3d223f4cd8b78b6d297a9d8167ebdedc0ffd1704241e5c9f1c2a1c1731 f¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = 88067129e7576c0dbd5d868cf5e189dd958fa4760551d8ea15c2fdabff218 9c43f730e71e543b537ccec0bd1497173b021ec6207c37ac930 pkSm = 7ac6049351075957923f00d5bd36c5299ee0b0724c53018c5d01ea239505e 63a4c76f77cb77cf1567fdcdeb5f720118f3b82c9dbfbbb659d¶
Input = 00 Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa 3833a26e9388336361686ff1f83df55046504dfecad8549ba112 BlindedElement = 7261bbc335c664ba788f1b1a1a4cd5190cc30e787ef277665ac 1d314f8861e3ec11854ce3ddd42035d9e0f5cddde324c332d8c880abc00eb EvaluationElement = b65b0074cb65cebbfe64a2ee018321742d1512fd6c14509b 6060c8db3143749bbed9d1896617759ec7c6ebfab032cf2b5eff5f5f5f46796c Proof = 3fd2c796e71873b9228ccb99c29baff392fda1a8b4711e4b75dab740ef05 d748317e7a136bd5daeaa78b7b3923ddbd67a4d9a7ea3da92836583217ac88426535 5ec9f45326f34178db77dac821f535e941fd8f8c50c06740a6cf04d0e49c50d1cbac cfd01c1e140a33193b832386410c ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b Output = dda56f0f50047483cb9a1db473ea9c3aab15d46d99526c091e3141299fc de4fdd0ce3bf654542687b90fe01aab2fdf06d523317122a24beea800893583735b1 e¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 64d37aed22a27f5191de1c1d69fadb899d8862b58eb4220029e036ec65fa 3833a26e9388336361686ff1f83df55046504dfecad8549ba112 BlindedElement = 88287e553939090b888ddc15913e1807dc4757215555e1c3a79 488ef311594729c7fa74c772a732b78440b7d66d0aa35f3bb316f1d93e1b2 EvaluationElement = 088947cd184cdaff715fb47130758238ecc1f05e049dbbd9 2cfef18a87e39e66728c79834f3fec33c96a57d34ed5c399e5e8c689331393ee Proof = 3771a89bfd4540c023db27251d5173640006d1ca76d4d7ad0a2236c2ee07 3dad7863e2d88414b9bd9c0b9fa1c61620e66bdefd304a2c120fbc959de3d8188a88 c0da281b1df1dbd2f4edb3c019363629bd2c8d5b5408792a1dabb985597e5905a9a2 2fcd55c5b3b34c20ce81ee91560b ProofRandomScalar = b1b748135d405ce48c6973401d9455bb8ccd18b01d0295c0 627f67661200dbf9569f73fbb3925daa043a070e5f953d80bb464ea369e5522b Output = fafbc029fef15f19545e5d1114275b21aab79bad25d7fff2fe1db99835e 706afde10b76a6766e61ac4064a9cb559d9afcede5a06cbc0178554608b13f9f751b 0¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = 3d4cd3c711a8ff4642aefcd9972c4a72d261188814286a483815a77e444a2 fb561f1748852f33a2f3bf7d86b0e27bf9fecad341bf286b116 pkSm = 2094323c2495a91d411d8967759cbcd694aef26ea0b5005e9e29a07d19452 b3b9b31d4ee14c51caa47f910e0553e402b050bf32011543c98¶
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¶
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¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 159749d750713afe245d2d39ccfaae8381c53ce92d098a9375ee70739c7ac 0bf¶
Input = 00 Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 03723a1e5c09b8b9c18d1dcbca29e8007e95f14f4732d9346d4 90ffc195110368d EvaluationElement = 030de02ffec47a1fd53efcdd1c6faf5bdc270912b8749e78 3c7ca75bb412958832 Output = a0b34de5fa4c5b6da07e72af73cc507cceeb48981b97b7285fc375345fe 495dd¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 03cc1df781f1c2240a64d1c297b3f3d16262ef5d4cf10273488 2675c26231b0838 EvaluationElement = 03a0395fe3828f2476ffcd1f4fe540e5a8489322d398be3c 4e5a869db7fcb7c52c Output = c748ca6dd327f0ce85f4ae3a8cd6d4d5390bbb804c9e12dcf94f853fece 3dcce¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = ca5d94c8807817669a51b196c34c1b7f8442fde4334a7121ae4736364312f ca6 pkSm = 03e17e70604bcabe198882c0a1f27a92441e774224ed9c702e51dd17038b1 02462¶
Input = 00 Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 02dd05901038bb31a6fae01828fd8d0e49e35a486b5c5d4b499 4013648c01277da EvaluationElement = 0209f33cab60cf8fe69239b0afbcfcd261af4c1c5632624f 2e9ba29b90ae83e4a2 Proof = e7c2b3c5c954c035949f1f74e6bce2ed539a3be267d1481e9ddb178533df 4c2664f69d065c604a4fd953e100b856ad83804eb3845189babfa5a702090d6fc5fa ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c e45c405d1348b7b1 Output = 0412e8f78b02c415ab3a288e228978376f99927767ff37c5718d420010a 645a1¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 03cd0f033e791c4d79dfa9c6ed750f2ac009ec46cd4195ca6fd 3800d1e9b887dbd EvaluationElement = 030d2985865c693bf7af47ba4d3a3813176576383d19aff0 03ef7b0784a0d83cf1 Proof = 2787d729c57e3d9512d3aa9e8708ad226bc48e0f1750b0767aaff73482c4 4b8d2873d74ec88aebd3504961acea16790a05c542d9fbff4fe269a77510db00abab ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c e45c405d1348b7b1 Output = 771e10dcd6bcd3664e23b8f2a710cfaaa8357747c4a8cbba03133967b5c 24f18¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 6ad2173efa689ef2c27772566ad7ff6e2d59b3b196f00219451fb2c89ee4d ae2 pkSm = 030d7ff077fddeec965db14b794f0cc1ba9019b04a2f4fcc1fa525dedf72e 2a3e3¶
Input = 00 Info = 7465737420696e666f Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 031563e127099a8f61ed51eeede05d747a8da2be329b40ba1f0 db0b2bd9dd4e2c0 EvaluationElement = 02c5e5300c2d9e6ba7f3f4ad60500ad93a0157e6288eb04b 67e125db024a2c74d2 Proof = f8a33690b87736c854eadfcaab58a59b8d9c03b569110b6f31f8bf7577f3 fbb85a8a0c38468ccde1ba942be501654adb106167c8eb178703ccb42bccffb9231a ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c e45c405d1348b7b1 Output = 193a92520bd8fd1f37accb918040a57108daa110dc4f659abe212636d24 5c592¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Info = 7465737420696e666f Blind = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 021a440ace8ca667f261c10ac7686adc66a12be31e3520fca31 7643a1eee9dcd4d EvaluationElement = 0208ca109cbae44f4774fc0bdd2783efdcb868cb4523d521 96f700210e777c5de3 Proof = 043a8fb7fc7fd31e35770cabda4753c5bf0ecc1e88c68d7d35a62bf2631e 875af4613641be2d1875c31d1319d191c4bbc0d04875f4fd03c31d3d17dd8e069b69 ProofRandomScalar = f9db001266677f62c095021db018cd8cbb55941d4073698c e45c405d1348b7b1 Output = 1e6d164cfd835d88a31401623549bf6b9b306628ef03a7962921d62bc5f fce8c¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = b16c4f85142a577411d0621516c6c48b928363575a9b27dca10e553de74af 0c2096ed9deed1792ee9665dcbcd4bd7c35¶
Input = 00 Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 02a36bc90e6db34096346eaf8b7bc40ee1113582155ad379700 3ce614c835a874343701d3f2debbd80d97cbe45de6e5f1f EvaluationElement = 033b7c36005ca1d8bb9e18198d6b379c662739bd65f716fc f3fdb384d61624b96c4ad3911b861ad8b1b24e85acc1613b05 Output = 91961a85dca85527b88ac94c1642c449e944ac463b9d1696bcd2efe6d38 f9cc8a2480f57b45536f3ce8062e8e54f16fb¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 02def6f418e3484f67a124a2ce1bfb19de7a4af568ede6a1ebb 2733882510ddd43d05f2b1ab5187936a55e50a847a8b900 EvaluationElement = 022317c418d5f836d4fcab18b887111a54b5015b54f4fcae e8b2edc7e79b1c7f24e0a1a8a548874679c8705a547b34447d Output = aa385f328a0ed4dd9af751f63d27d10a41226ec095a4eec5237071579ac da69ccbc0d0c8a2ab4d033934e7987f2b10d4¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = afc3a71e59eaa2684d4da6f01f41977471e3efeefb11454168f9fecf384cf f934332355d631f83d3aec9bd36a940be5a pkSm = 02139a4c608f418c458409bbc9970796bd784cf5a4251578276d5a005706a 130c75e4d440e463fa3ca9bd56394a00ae470¶
Input = 00 Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 02d338c05cbecb82de13d6700f09cb61190543a7b7e2c6cd4fc a56887e564ea82653b27fdad383995ea6d02cf26d0e24d9 EvaluationElement = 0202df7145c1fb3cf57fd4bc062d58d06034a1ae63b02b91 ba4f57f57187f98f7cf026b5bc9a4ea1aa6e40b94b8f53a826 Proof = 23e19b916ba705bd55d541dc11af23a99d2754ac46aa9b8158f3274d69b4 75988a377e4ded17a319fbdc2ac1391cb4ac74b59787298ee213976accea1cada09b aeb5303a1b133fff96a08562864d19751a57144d3477e4c59935222f29c3e728 ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62 c095021db018cd8cbb55941d4073698ce45c405d1348b7b1 Output = 5e6261bfb3d397c8f90dfda0782a8450c70013489cffe8f60c205843d55 dd350da52d6fb2e96d9c779e083c5acea67b4¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 02f27469e059886f221be5f2cca03d2bdc61e55221721c3b3e5 6fc012e36d31ae5f8dc058109591556a6dbd3a8c69c433b EvaluationElement = 0342050f2c95bc49cf48442703bb772335113dd9c54b6280 3b2cfc3a2aed78030a6a27fa088bf491c290c7e905a3a1c781 Proof = 13a5a0ea31ce00a35d5e90cd2d00ff0b830d3f87f23b757fa547a592b7e9 be955528d81852869fec6d2c986a75c09f628bf3ff14d18a5c7a8b4b6bb22dced106 34590314c4415b5f420257694052832977dfaac46bd119e8ef8c3126f3a0d312 ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62 c095021db018cd8cbb55941d4073698ce45c405d1348b7b1 Output = 0a3b70080afe17322a0c15411dcb7b9d64ca8a6730174446c2407499c2c 44f2a029ab7a48d1dbebbc4507539c2a2ee35¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3 KeyInfo = 74657374206b6579 skSm = 79f09d6067bc438dcecf3299af6c38f0045681a28658a73162a5c6f1700aa aca21c27b9711d84e38b56fd81710488a5e pkSm = 023d5a2f4cf07f823e317a852935d59f4d1e426ed41d87eab1734d660818a fe5ede9713836d16e31edcb55ecbad35f3c9e¶
Input = 00 Info = 7465737420696e666f Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 03859b36b95e6564faa85cd3801175eda2949707f6aa0640ad0 93cbf8ad2f58e762f08b56b2a1b42a64953aaf49cbf1ae3 EvaluationElement = 0350c1f39f77834618ff2f98b00ad184f65e83c5f04b469b 4f042b62c9c46cd9e50dfc946f5ee9a2a53c86824197d42dc4 Proof = cd845a3c6329e3d1f5c9e6a2985c613fc1f71168589eac679387bed21814 1aa2e1b92692ff3224eb30f4f17569a53ae0f302f0218cece17ac09b58663685847b df719c073ad97f0fbee5acb53c175ece3c96dad6d7b926a4c2439d9a9ced9d45 ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62 c095021db018cd8cbb55941d4073698ce45c405d1348b7b1 Output = 6a7b0005c9a93a50b0e8e5b70d5a903610731ca1e6dc912ed18c2c7e840 e9b4fd0734e3f070936d9b816132c9eafaa62¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Info = 7465737420696e666f Blind = 504650f53df8f16f6861633388936ea23338fa65ec36e0290022b48eb562 889d89dbfa691d1cde91517fa222ed7ad364 BlindedElement = 03f7efcb4aaf000263369d8a0621cb96b81b3206e99876de2a0 0699ed4c45acf3969cd6e2319215395955d3f8d8cc1c712 EvaluationElement = 02050d70ca554bde7caadbcbc94282ffdf99ae7a86097a88 2c585222d200cb08644fa63500dbe75e41027c36bb4eb902ae Proof = 6900d5f3c87c4cb64d976130ba4530153de4be61975f4151baea07b1f9bf 49b420b1639be9a96d68a40a42da4cf3da594449ba20a1868b9626a39ca9cd6ee609 5a7435f1b0bfd83dc4baa15f375bf0bed3e7974a05d87bc4040a608bd6ad7216 ProofRandomScalar = 803d955f0e073a04aa5d92b3fb739f56f9db001266677f62 c095021db018cd8cbb55941d4073698ce45c405d1348b7b1 Output = fcc8d222669da6b61090d961a2c6cce490f0f798d72b6b1abbe9c12a087 45f41b43c29cdca294ddc72d1e207360cffe4¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 00df1c651aa393bcd50c7ecf06f8472706dcb2c41ceadca770569d10be389 0f7102a720e36fc7b84fca500d76715b9356f7b4bdca20aff5ef4cd7bb344b0b2c01 d98¶
Input = 00 Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 0300e78bf846b0e1e1a3c320e353d758583cd876df56100a3a1 e62bacba470fa6e0991be1be80b721c50c5fd0c672ba764457acc18c6200704e9294 fbf28859d916351 EvaluationElement = 0301d6fdc5bdc3434afce77ff15072fcd99b83e608718bac 4d05539e7e2bae12dd5475a0de4938eb3be5c1bf37f0b2c99daa9ab84cadbf068d7b 18a5fca8de7a99790e Output = e18fc074d9c79168e9ce9f386969a8a999087b2b84136c952ffac454674 f92475cb78b33fe347762924bfaae7182bb9a8a043a157c862d1d93ca12ff16ad205 5¶
Input = 5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a Blind = 00d1dccf7a51bafaf75d4a866d53d8cafe4d504650f53df8f16f68616333 88936ea23338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7a d364 BlindedElement = 0300c28e57e74361d87e0c1874e5f7cc1cc796d61f9cad50427 cf54655cdb455613368d42b27f94bf66f59f53c816db3e95e68e1b113443d66a99b3 693bab88afb556b EvaluationElement = 0301bea09ae35a633a769a3af78f491325e7d66ed0939774 df74faab4e50e344031a9ec28d8ccf95997b8a300a42bee00539bfc07c3355904278 57d2fc6e2e5d1c0b8b Output = 07c31b9b01c59b3d8367ba70e521103a3b41e544613c372b445b55e4012 4093e060b48a15c7dfbee5f00e147e180a676fc1e3343453175f7ed22ba99a1f96a2 d¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 015cc2356215d2d35d84f0ade8633d8da044db46b5e7eee56b60b956e9f68 4a8a751fbf7de3d17fa9567c93b8c951030ec23ca1e4b88c0686a941d2cf809081c5 86a pkSm = 0301b9339969103060f1761f4b439a88b71ba0c28a95cc12dbe051cbeffaa adc1305edbf11e0b8927a59fa2cd436f1a780d0d4586966d5964195fcee03d28b64b fec5c¶
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¶
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¶
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¶
Seed = a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a3a 3a3 KeyInfo = 74657374206b6579 skSm = 01f494b76f11776ffc15f6b5613110e7db8e4a6a87721714c1e86289c192b 1ec97d358eb0e2c445c2475f775e7b389ae35c5001ce337ae65ef5c67c7b22ca3d90 ce0 pkSm = 0300cb19d7aadaf3f2819ceba73a41e998eb5103b2d95e4d077b3c3b5a848 e9a8e782a259066a43b9fc3503d9a38c79ccd59df77bed87cc5d312bb42cbe381d01 27d3d¶
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¶
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¶
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¶