<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.30 (Ruby 3.4.8) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-privacypass-arc-crypto-00" category="info" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.31.0 -->
  <front>
    <title abbrev="ARC Cryptography">Anonymous Rate-Limited Credentials Cryptography</title>
    <seriesInfo name="Internet-Draft" value="draft-privacypass-arc-crypto-00"/>
    <author initials="C." surname="Yun" fullname="Cathie Yun">
      <organization>Apple, Inc.</organization>
      <address>
        <email>cathieyun@gmail.com</email>
      </address>
    </author>
    <author initials="C. A." surname="Wood" fullname="Christopher A. Wood">
      <organization>Apple, Inc.</organization>
      <address>
        <email>caw@heapingbits.net</email>
      </address>
    </author>
    <date year="2026" month="January" day="26"/>
    <abstract>
      <?line 55?>

<t>This document specifies the Anonymous Rate-Limited Credential (ARC) protocol,
a specialization of keyed-verification anonymous credentials with support for
rate limiting. ARC credentials can be presented from client to server up to
some fixed number of times, where each presentation is cryptographically bound
to client secrets and application-specific public information, such that each
presentation is unlinkable from the others as well as the original credential
creation. ARC is useful in applications where a server needs to throttle or
rate-limit access from anonymous clients.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://ietf-wg-privacypass.github.io/draft-arc/draft-privacypass-arc-crypto.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-privacypass-arc-crypto/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        PRIVACYPASS Privacy Pass mailing list (<eref target="mailto:privacy-pass@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/privacy-pass"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/privacy-pass/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/ietf-wg-privacypass/draft-arc"/>.</t>
    </note>
  </front>
  <middle>
    <?line 66?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>This document specifies the Anonymous Rate-Limited Credential (ARC) protocol,
a specialization of keyed-verification anonymous credentials with support for
rate limiting.</t>
      <t>ARC is privately verifiable (keyed-verification), yet differs from similar token-based
protocols in that each credential can be presented multiple times without violating
unlinkability of different presentations. Servers issue credentials to clients that
are cryptographically bound to client secrets and some public information.
Afterwards, clients can present this credential to the server up to some fixed
number of times, where each presentation provides proof that it was derived
from a valid (previously issued) credential and bound to some public information.
Each presentation is pairwise unlinkable, meaning the server cannot link any two
presentations to the same client credential, nor can the server link a presentation
to the preceding credential issuance flow. Notably, the maximum number of
presentations from a credential is fixed by the application.</t>
      <t>ARC is useful in settings where applications require a fixed number of zero-knowledge
proofs about client secrets that can also be cryptographically bound to some public
information. This capability lets servers use credentials in applications that need
throttled or rate-limited access from anonymous clients.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
      <section anchor="notation-and-terminology">
        <name>Notation and Terminology</name>
        <t>The following functions and notation are used throughout the document.</t>
        <ul spacing="normal">
          <li>
            <t>concat(x0, ..., xN): Concatenation of byte strings. For example,
concat(0x01, 0x0203, 0x040506) = 0x010203040506.</t>
          </li>
          <li>
            <t>bytes_to_int and int_to_bytes: Convert a byte string to and from a non-negative integer.
bytes_to_int and int_to_bytes are implemented as OS2IP and I2OSP as described in
<xref target="RFC8017"/>, respectively. Note that these functions operate on byte strings
in big-endian byte order.</t>
          </li>
          <li>
            <t>random_integer_uniform(M, N): Generate a random, uniformly distributed integer R
between M inclusive and N exclusive, i.e., M &lt;= R &lt; N.</t>
          </li>
          <li>
            <t>random_integer_uniform_excluding_set(M, N, S): Generate a random, uniformly
distributed integer R between M inclusive and N exclusive, i.e., M &lt;= R &lt; N,
such that R does not exist in the set of integers S.</t>
          </li>
        </ul>
        <t>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.</t>
        <t>The notation <tt>T U[N]</tt> refers to an array called U containing N items of type
T. The type <tt>opaque</tt> means one single byte of uninterpreted data. Items of
the array are zero-indexed and referred as <tt>U[j]</tt> such that 0 &lt;= j &lt; N.
The notation <tt>{T}</tt> refers to a set consisting of elements of type <tt>T</tt>.
For any object <tt>x</tt>, we write <tt>len(x)</tt> to denote its length in bytes.</t>
        <t>String values such as "CredentialRequest", "CredentialResponse", "Presentation", and "Tag"
are ASCII string literals.</t>
        <t>The following terms are used throughout this document.</t>
        <ul spacing="normal">
          <li>
            <t>Client: Protocol initiator. Creates a credential request, and uses the
corresponding server response to make a credential. The client can
make multiple presentations of this credential.</t>
          </li>
          <li>
            <t>Server: Computes a response to a credential request, with its
server private keys. Later the server can verify the client's presentations
with its private keys. Learns nothing about the client's secret attributes,
and cannot link a client's request/response and presentation steps.</t>
          </li>
        </ul>
        <!-- TODO(caw): define these terms:
- tag
- attribute
- requestContext
- presentationContext
- presentationLimit
- presentation
-->

</section>
    </section>
    <section anchor="preliminaries">
      <name>Preliminaries</name>
      <t>The construction in this document has one primary dependency:</t>
      <ul spacing="normal">
        <li>
          <t><tt>Group</tt>: A prime-order group implementing the API described below in <xref target="pog"/>.
See <xref target="ciphersuites"/> for specific instances of groups.</t>
        </li>
      </ul>
      <section anchor="pog">
        <name>Prime-Order Group</name>
        <t>In this document, we assume the construction of an additive, prime-order
group <tt>Group</tt> 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.
In the ARC setting, there are two fixed generator elements (generatorG, generatorH).
Such groups are uniquely determined by the choice of the prime <tt>p</tt> that defines the
order of the group. (There may, however, exist different representations
of the group for a single <tt>p</tt>. <xref target="ciphersuites"/> lists specific groups which
indicate both order and representation.)</t>
        <t>The fundamental group operation is addition <tt>+</tt> with identity element
<tt>I</tt>. For any elements <tt>A</tt> and <tt>B</tt> of the group, <tt>A + B = B + A</tt> is
also a member of the group. Also, for any <tt>A</tt> in the group, there exists an element
<tt>-A</tt> such that <tt>A + (-A) = (-A) + A = I</tt>. Scalar multiplication by <tt>r</tt> is
equivalent to the repeated application of the group operation on an
element A with itself <tt>r-1</tt> times, this is denoted as <tt>r*A = A + ... + A</tt>.
For any element <tt>A</tt>, <tt>p*A=I</tt>. The case when the scalar multiplication is
performed on the group generator is denoted as <tt>ScalarMultGen(r)</tt>.
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 <tt>GF(p)</tt>, a prime field of order p, and are
represented as the set of integers defined by <tt>{0, 1, ..., p-1}</tt>.
This document uses types
<tt>Element</tt> and <tt>Scalar</tt> to denote elements of the group and its set of
scalars, respectively.</t>
        <t>We now detail a number of member functions that can be invoked on a
prime-order group.</t>
        <ul spacing="normal">
          <li>
            <t>Order(): Outputs the order of the group (i.e. <tt>p</tt>).</t>
          </li>
          <li>
            <t>Identity(): Outputs the identity element of the group (i.e. <tt>I</tt>).</t>
          </li>
          <li>
            <t>Generator(): Outputs the fixed generator of the group.</t>
          </li>
          <li>
            <t>HashToGroup(x, info): Deterministically maps
an array of bytes <tt>x</tt> with domain separation value <tt>info</tt> to an element of <tt>Group</tt>. The map must ensure that,
for any adversary receiving <tt>R = HashToGroup(x, info)</tt>, it is
computationally difficult to reverse the mapping.
Security properties of this function are described
in <xref target="I-D.irtf-cfrg-hash-to-curve"/>.</t>
          </li>
          <li>
            <t>HashToScalar(x, info): Deterministically maps
an array of bytes <tt>x</tt> with domain separation value <tt>info</tt> to an element in GF(p).
Security properties of this function are described in <xref section="10.5" sectionFormat="comma" target="I-D.irtf-cfrg-hash-to-curve"/>.</t>
          </li>
          <li>
            <t>RandomScalar(): Chooses at random a non-zero element in GF(p).</t>
          </li>
          <li>
            <t>ScalarInverse(s): Returns the inverse of input <tt>Scalar</tt> <tt>s</tt> on <tt>GF(p)</tt>.</t>
          </li>
          <li>
            <t>SerializeElement(A): Maps an <tt>Element</tt> <tt>A</tt>
to a canonical byte array <tt>buf</tt> of fixed length <tt>Ne</tt>.</t>
          </li>
          <li>
            <t>DeserializeElement(buf): Attempts to map a byte array <tt>buf</tt> to
an <tt>Element</tt> <tt>A</tt>, 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 <tt>A</tt> is the identity element of
the group; see <xref target="ciphersuites"/> for group-specific input validation steps.</t>
          </li>
          <li>
            <t>SerializeScalar(s): Maps a <tt>Scalar</tt> <tt>s</tt> to a canonical
byte array <tt>buf</tt> of fixed length <tt>Ns</tt>.</t>
          </li>
          <li>
            <t>DeserializeScalar(buf): Attempts to map a byte array <tt>buf</tt> to a <tt>Scalar</tt> <tt>s</tt>.
This function can raise a DeserializeError if deserialization fails; see
<xref target="ciphersuites"/> for group-specific input validation steps.</t>
          </li>
        </ul>
        <t>For each group, there exists two distinct generators, generatorG and
generatorH, generatorG = G.Generator() and generatorH = G.HashToGroup(G.SerializeElement(generatorG), "generatorH").
The group member functions GeneratorG() and GeneratorH() are shorthand
for returning generatorG and generatorH, respectively.</t>
        <t><xref target="ciphersuites"/> contains details for the implementation of this interface
for different prime-order groups instantiated over elliptic curves.</t>
      </section>
    </section>
    <section anchor="arc-protocol">
      <name>ARC Protocol</name>
      <t>The ARC protocol is a two-party protocol run between client and server
consisting of three distinct phases:</t>
      <ol spacing="normal" type="1"><li>
          <t>Key generation. In this phase, the server generates its private and public
keys to be used for the remaining phases. This phase is described in <xref target="setup"/>.</t>
        </li>
        <li>
          <t>Credential issuance. In this phase, the client and server interact to issue
the client a credential that is cryptographically bound to client secrets.
This phase is described in <xref target="issuance"/>.</t>
        </li>
        <li>
          <t>Presentation. In this phase, the client uses the credential to create a "presentation"
to the server, where the server learns nothing more than whether or not the
presentation is valid and corresponds to some previously issued credential,
without learning which credential it corresponds to. This phase is described
in <xref target="presentation"/>.</t>
        </li>
      </ol>
      <t>This protocol bears resemblance to anonymous token protocols, such as those built on
Blind RSA <xref target="BLIND-RSA"/> and Oblivious Pseudorandom Functions <xref target="OPRFS"/>
with one critical distinction: unlike anonymous tokens, an anonymous credential can be
used multiple times to create unlinkable presentations (up to the fixed presentation
limit). This means that a single issuance invocation can drive multiple presentation
invocations, whereas with anonymous tokens, each presentation invocation requires
exactly one issuance invocation. As a result, credentials are generally longer lived
than tokens. Applications configure the credential presentation limit after the
credential is issued such that client and server agree on the limit during presentation.
Servers are responsible for ensuring this limit is not exceeded. Clients that exceed
the agreed-upon presentation limit break the unlinkability guarantees provided by
the protocol.</t>
      <t>The rest of this section describes the three phases of the ARC protocol.</t>
      <section anchor="setup">
        <name>Key Generation</name>
        <t>In the key generation phase, the server generates its private and public
keys, denoted ServerPrivateKey and ServerPublicKey, as follows.</t>
        <artwork><![CDATA[
Input: None
Output:
- ServerPrivateKey:
  - x0: Scalar
  - x1: Scalar
  - x2: Scalar
  - x0Blinding: Scalar
- ServerPublicKey:
  - X0: Element
  - X1: Element
  - X2: Element

Parameters
- Group G

def SetupServer():
  x0 = G.RandomScalar()
  x1 = G.RandomScalar()
  x2 = G.RandomScalar()
  x0Blinding = G.RandomScalar()
  X0 = x0 * G.GeneratorG() + x0Blinding * G.GeneratorH()
  X1 = x1 * G.GeneratorH()
  X2 = x2 * G.GeneratorH()
  return ServerPrivateKey(x0, x1, x2, x0Blinding), ServerPublicKey(X0, X1, X2)
]]></artwork>
        <t>The server public keys can be serialized as follows:</t>
        <artwork><![CDATA[
struct {
  uint8 X0[Ne]; // G.SerializeElement(X0)
  uint8 X1[Ne]; // G.SerializeElement(X1)
  uint8 X2[Ne]; // G.SerializeElement(X2)
} ServerPublicKey;
]]></artwork>
        <t>The length of this encoded response structure is <tt>NserverPublicKey = 3*Ne</tt>.</t>
      </section>
      <section anchor="issuance">
        <name>Issuance</name>
        <t>The purpose of the issuance phase is for the client and server to cooperatively compute a credential
that is cryptographically bound to the client's secrets. Clients do not choose these secrets;
they are computed by the protocol.</t>
        <t>The issuance phase of the protocol requires clients to know the server public key a priori, as well as
an arbitrary, application-specific request context. It requires no other input. It consists of three
distinct steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>The client generates and sends a credential request to the server. This credential request contains a
proof that the request is valid with respect to the client's secrets and request context. See
<xref target="issuance-step1"/> for details about this step.</t>
          </li>
          <li>
            <t>The server validates the credential request. If valid, it computes a credential response with the server
private keys. The response includes a proof that the credential response is valid with respect to the
server keys. The server sends the response to the client. See <xref target="issuance-step2"/> for details about this
step.</t>
          </li>
          <li>
            <t>The client finalizes the credential by processing the server response. If valid, this step yields a
credential that can then be used in the presentation phase of the protocol. See <xref target="issuance-step3"/> for
details about this step.</t>
          </li>
        </ol>
        <t>Each of these steps are described in the following subsections.</t>
        <section anchor="issuance-step1">
          <name>Credential Request</name>
          <t>Given a request context, the process for creating a credential request is as follows:</t>
          <artwork><![CDATA[
(clientSecrets, request) = CreateCredentialRequest(requestContext)

Inputs:
- requestContext: Data, context for the credential request

Outputs:
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.
- clientSecrets:
  - m1: Scalar, first secret.
  - m2: Scalar, second secret.
  - r1: Scalar, blinding factor for first secret.
  - r2: Scalar, blinding factor for second secret.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

def CreateCredentialRequest(requestContext):
  m1 = G.RandomScalar()
  m2 = G.HashToScalar(requestContext, "requestContext")
  r1 = G.RandomScalar()
  r2 = G.RandomScalar()
  m1Enc = m1 * generatorG + r1 * generatorH
  m2Enc = m2 * generatorG + r2 * generatorH
  requestProof = MakeCredentialRequestProof(m1, m2, r1, r2, m1Enc, m2Enc)
  request = (m1Enc, m2Enc, requestProof)
  clientSecrets = (m1, m2, r1, r2)
  return (clientSecrets, request)
]]></artwork>
          <t>See <xref target="request-proof"/> for more details on the generation of the credential request proof.</t>
          <t>The resulting request can be serialized as follows.</t>
          <artwork><![CDATA[
struct {
  uint8 m1Enc[Ne];
  uint8 m2Enc[Ne];
  uint8 challenge[Ns];
  uint8 response0[Ns];
  uint8 response1[Ns];
  uint8 response2[Ns];
  uint8 response3[Ns];
} CredentialRequest;
]]></artwork>
          <t>The length of this encoded request structure is <tt>Nrequest = 2*Ne + 5*Ns</tt>.</t>
        </section>
        <section anchor="issuance-step2">
          <name>Credential Response</name>
          <t>Given a credential request and server public and private keys, the process
for creating a credential response is as follows.</t>
          <sourcecode type="pseudocode"><![CDATA[
response = CreateCredentialResponse(serverPrivateKey, serverPublicKey, request)

Inputs:
- serverPrivateKey:
  - x0: Scalar (private), server private key 0.
  - x1: Scalar (private), server private key 1.
  - x2: Scalar (private), server private key 2.
  - x0Blinding: Scalar (private), blinding value for x0.
- serverPublicKey:
  - X0: Element, server public key 0.
  - X1: Element, server public key 1.
  - X2: Element, server public key 2.
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.

Outputs:
- U: Element, a randomized generator for the response, `b*G`.
- encUPrime: Element, encrypted UPrime.
- X0Aux: Element, auxiliary point for X0.
- X1Aux: Element, auxiliary point for X1.
- X2Aux: Element, auxiliary point for X2.
- HAux: Element, auxiliary point for generatorH.
- responseProof: ZKProof, a proof of correct generation of
  U, encUPrime, server public keys, and auxiliary points.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- VerifyError, raised when response verification fails

def CreateCredentialResponse(serverPrivateKeys, serverPublicKey, request):
  if VerifyCredentialRequestProof(request) == false:
    raise VerifyError

  b = G.RandomScalar()
  U = b * generatorG
  encUPrime = b * (serverPublicKey.X0 +
        serverPrivateKeys.x1 * request.m1Enc +
        serverPrivateKeys.x2 * request.m2Enc)
  X0Aux = b * serverPrivateKeys.x0Blinding * generatorH
  X1Aux = b * serverPublicKey.X1
  X2Aux = b * serverPublicKey.X2
  HAux = b * generatorH

  responseProof = MakeCredentialResponseProof(serverPrivateKey,
    serverPublicKey, request, b, U, encUPrime, X0Aux, X1Aux, X2Aux, HAux)
  return (U, encUPrime, X0Aux, X1Aux, X2Aux, HAux, responseProof)
]]></sourcecode>
          <t>The resulting response can be serialized as follows. See <xref target="response-proof"/> for more details on the generation of the credential response proof.</t>
          <artwork><![CDATA[
struct {
  uint8 U[Ne];
  uint8 encUPrime[Ne];
  uint8 X0Aux[Ne];
  uint8 X1Aux[Ne];
  uint8 X2Aux[Ne];
  uint8 HAux[Ne];
  uint8 challenge[Ns];
  uint8 response0[Ns];
  uint8 response1[Ns];
  uint8 response2[Ns];
  uint8 response3[Ns];
  uint8 response4[Ns];
  uint8 response5[Ns];
  uint8 response6[Ns];
} CredentialResponse
]]></artwork>
          <t>The length of this encoded response structure is <tt>Nresponse = 6*Ne + 8*Ns</tt>.</t>
        </section>
        <section anchor="issuance-step3">
          <name>Finalize Credential</name>
          <t>Given a credential request and response, server public keys, and the client
secrets produced when creating a credential request, the process for
finalizing the issuance flow and creating a credential is as follows.</t>
          <artwork><![CDATA[
credential = FinalizeCredential(clientSecrets, serverPublicKey, request, response)

Inputs:
- clientSecrets:
  - m1: Scalar, first secret.
  - m2: Scalar, second secret.
  - r1: Scalar, blinding factor for first secret.
  - r2: Scalar, blinding factor for second secret.
- serverPublicKey: ServerPublicKey, shared with the client out-of-band
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.
- response:
  - U: Element, a randomized generator for the response. `b*G`.
  - encUPrime: Element, encrypted UPrime.
  - X0Aux: Element, auxiliary point for X0.
  - X1Aux: Element, auxiliary point for X1.
  - X2Aux: Element, auxiliary point for X2.
  - HAux: Element, auxiliary point for generatorH.
  - responseProof: ZKProof, a proof of correct generation of U, encUPrime, server public keys, and auxiliary points.

Outputs:
- credential:
  - m1: Scalar, client's first secret.
  - U: Element, a randomized generator for the response. `b*G`.
  - UPrime: Element, the MAC over the server's private keys and the client's secret secrets.
  - X1: Element, server public key 1.

Exceptions:
- VerifyError, raised when response verification fails

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

def FinalizeCredential(clientSecrets, serverPublicKey, request, response):
  if VerifyCredentialResponseProof(serverPublicKey, response, request) == false:
    raise VerifyError
  UPrime = response.encUPrime - response.X0Aux - clientSecrets.r1 * response.X1Aux - clientSecrets.r2 * response.X2Aux
  return (clientSecrets.m1, response.U, UPrime, serverPublicKey.X1)
]]></artwork>
        </section>
      </section>
      <section anchor="presentation">
        <name>Presentation</name>
        <t>The purpose of the presentation phase is for the client to create a "presentation" to the server
which can be verified using the server private key. This phase is non-interactive, i.e., there is
no state stored between client and server in order to produce and then verify a presentation.
Client and server agree upon a fixed limit of presentations in order to create and verify
presentations; presentations will not verify correctly if the client and server use different
limits.</t>
        <t>This phase consists of three steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>The client creates a presentation state for a given presentation context and presentation limit.
This state is used to produce a fixed amount of presentations.</t>
          </li>
          <li>
            <t>The client creates a presentation from the presentation state and sends it to the server.
The presentation is cryptographically bound to the state's presentation context, and
contains proof that the presentation is valid with respect to the presentation context.
Moreover, the presentation contains proof that the nonce (an integer) associated with this
presentation is within the presentation limit.</t>
          </li>
          <li>
            <t>The server verifies the presentation with respect to the presentation context and presentation
limit.</t>
          </li>
        </ol>
        <t>Details for each each of these steps are in the following subsections.</t>
        <section anchor="presentation-state">
          <name>Presentation State</name>
          <t>Presentation state is used to track the number of presentations for a given credential.
This state is important for ARC's unlinkability goals: reuse of state can break
unlinkability properties of credential presentations. State is initialized
with a credential, presentation context, and presentation limit. It is then mutated
after each presentation construction (as described in <xref target="presentation-construction"/>).</t>
          <artwork><![CDATA[
state = MakePresentationState(credential, presentationContext, presentationLimit)

Inputs:
- credential:
  - m1: Scalar, client's first secret.
  - U: Element, a randomized generator for the response `b*G`.
  - UPrime: Element, the MAC over the server's private keys and the client's secrets.
  - X1: Element, server public key 1.
- presentationContext: Data (public), used for presentation tag computation.
- presentationLimit: Integer, the fixed presentation limit.

Outputs:
- credential
- presentationContext: Data (public), used for presentation tag computation.
- presentationNonceSet: {Integer}, the set of nonces that have been used for this presentation
- presentationLimit: Integer, the fixed presentation limit.

def MakePresentationState(credential, presentationContext, presentationLimit):
  return PresentationState(credential, presentationContext, [], presentationLimit)
]]></artwork>
        </section>
        <section anchor="presentation-construction">
          <name>Presentation Construction</name>
          <t>Creating a presentation requires a credential, presentation context, and presentation limit.
This process is necessarily stateful on the client since the number of times a credential
is used for a given presentation context cannot exceed the presentation limit; doing so
would break presentation unlinkability, as two presentations created with the same nonce
can be directly compared for equality (via the "tag"). As a result, the process for creating
a presentation accepts as input a presentation state and then outputs an updated presentation
state.</t>
          <artwork><![CDATA[
newState, nonce, presentation = Present(state)

Inputs:
state: input PresentationState
  - credential
  - presentationContext: Data (public), used for presentation tag computation.
  - presentationNonceSet: {Integer}, the set of nonces that have been used for this presentation
  - presentationLimit: Integer, the fixed presentation limit.

Outputs:
- newState: updated PresentationState
- nonce: Integer, the nonce associated with this presentation.
- presentation:
  - U: Element, re-randomized from the U in the response.
  - UPrimeCommit: Element, a public key to the issued UPrime.
  - m1Commit: Element, a public key to the client secret (m1).
  - tag: Element, the tag element used for enforcing the presentation limit.
  - presentationProof: ZKProof, a proof of correct generation of the presentation.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- LimitExceededError, raised when the presentation count meets or exceeds the presentation limit for the given presentation context

def Present(state):
  if len(state.presentationNonceSet) >= state.presentationLimit:
    raise LimitExceededError

  a = G.RandomScalar()
  r = G.RandomScalar()
  z = G.RandomScalar()

  U = a * state.credential.U
  UPrime = a * state.credential.UPrime
  UPrimeCommit = UPrime + r * generatorG
  m1Commit = state.credential.m1 * U + z * generatorH

  # This step mutates the state by keeping track of
  # what nonces have already been spent.
  nonce = random_integer_uniform_excluding_set(0,
    state.presentationLimit, state.presentationNonceSet)
  state.presentationNonceSet.add(nonce)

  generatorT = G.HashToGroup(presentationContext, "Tag")
  tag = (credential.m1 + nonce)^(-1) * generatorT
  V = z * credential.X1 - r * generatorG
  m1Tag = state.credential.m1 * tag

  presentationProof = MakePresentationProof(U, UPrimeCommit, m1Commit, tag, generatorT, credential, V, r, z, nonce, m1Tag)

  presentation = (U, UPrimeCommit, m1Commit, tag, presentationProof)

  return state, nonce, presentation
]]></artwork>
          <t>OPEN ISSUE: should the tag also fold in the presentation limit?</t>
          <t>The resulting presentation can be serialized as follows. See <xref target="presentation-proof"/>
for more details on the generation of the presentation proof.</t>
          <artwork><![CDATA[
struct {
  uint8 U[Ne];
  uint8 UPrimeCommit[Ne];
  uint8 m1Commit[Ne];
  uint8 tag[Ne];
  uint8 challenge[Ns];
  uint8 response0[Ns];
  uint8 response1[Ns];
  uint8 response2[Ns];
  uint8 response3[Ns];
} Presentation
]]></artwork>
          <t>The length of this structure is <tt>Npresentation = 4*Ne + 5*Ns</tt>.</t>
        </section>
        <section anchor="presentation-verification">
          <name>Presentation Verification</name>
          <t>The server processes the presentation by verifying the presentation proof against server-computed
values, and performing a check that the presentation conforms to the presentation limit.</t>
          <artwork><![CDATA[
validity, tag = VerifyPresentation(
  serverPrivateKey,
  serverPublicKey,
  requestContext,
  presentationContext,
  nonce,
  presentation,
  presentationLimit)

Inputs:
- serverPrivateKey:
  - x0: Scalar (private), server private key 0.
  - x1: Scalar (private), server private key 1.
  - x2: Scalar (private), server private key 2.
  - x0Blinding: Scalar (private), blinding value for x0.
- serverPublicKey:
  - X0: Element, server public key 0.
  - X1: Element, server public key 1.
  - X2: Element, server public key 2.
- requestContext: Data, context for the credential request.
- presentationContext: Data (public), used for presentation tag computation.
- nonce: Integer, the nonce associated with this presentation.
- presentation:
  - U: Element, re-randomized from the U in the response.
  - UPrimeCommit: Element, a public key to the issued UPrime.
  - m1Commit: Element, a public key to the client secret (m1).
  - tag: Element, the tag element used for enforcing the presentation limit.
  - presentationProof: ZKProof, a proof of correct generation of the presentation.
- presentationLimit: Integer, the fixed presentation limit.

Outputs:
- validity: Boolean, True if the presentation is valid, False otherwise.
- tag: Bytes, the value of the presentation tag used for rate limiting.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- InvalidNonceError, raised when the nonce associated with the presentation is invalid

def VerifyPresentation(
  serverPrivateKey,
  serverPublicKey,
  requestContext,
  presentationContext,
  nonce,
  presentation,
  presentationLimit):

  if nonce < 0 or nonce > presentationLimit:
    raise InvalidNonceError

  generatorT = G.HashToGroup(presentationContext, "Tag")
  m1Tag = generatorT - (nonce * presentation.tag)

  validity = VerifyPresentationProof(
    serverPrivateKey,
    serverPublicKey,
    requestContext,
    presentationContext,
    presentation,
    m1Tag)

  return validity, presentation.tag
]]></artwork>
          <t>Implementation-specific steps: the server must perform a check that the tag (presentation.tag) has
not previously been seen, to prevent double spending. It then stores the tag for use in future double
spending checks. To reduce the overhead of performing double spend checks, the server can store and
look up the tags corresponding to the associated requestContext and presentationContext values.</t>
        </section>
      </section>
    </section>
    <section anchor="zero-knowledge-proofs">
      <name>Zero-Knowledge Proofs</name>
      <t>This section describes a Schnorr proof compiler that is used for the construction of other proofs needed throughout
the ARC protocol. <xref target="compiler"/> describes the compiler, and the remaining sections describe how it is used for
the purposes of producing ARC proofs.</t>
      <section anchor="compiler">
        <name>Schnorr Compiler</name>
        <t>The compiler specified in this section automates the Fiat-Shamir transform that is often used to
transform interactive zero-knowledge proofs into non-interactive proofs such that they can be used
to non-interactively prove various statements of importance in higher-level protocols, such as ARC.
The compiler consists of a prover and verifier role. The prover constructs a transcript for the
proof and then applies the Fiat-Shamir heuristic to generate the resulting challenge and response
values. The verifier reconstructs the same transcript to verify the proof.</t>
        <t>The prover and verifier roles are specified below in <xref target="prover"/> and <xref target="verifier"/>, respectively.</t>
        <section anchor="prover">
          <name>Prover</name>
          <t>The prover role consists of four functions:</t>
          <ul spacing="normal">
            <li>
              <t>AppendScalar: This function adds a scalar representation to the transcript.</t>
            </li>
            <li>
              <t>AppendElement: This function adds an element representation to the transcript.</t>
            </li>
            <li>
              <t>Constrain: This function applies an explicit constraint to the proof, where the constraint is expressed as equality between some element and a linear combination of scalar and element representations. An example constraint might be <tt>Z = aX + bY</tt>, for scalars <tt>a</tt>, <tt>b</tt>, and elements
<tt>X</tt>, <tt>Y</tt>, <tt>Z</tt>.</t>
            </li>
            <li>
              <t>Prove: This function applies the Fiat-Shamir heuristic to the protocol transcript and set of
constraints to produce a zero-knowledge proof that can be verified.</t>
            </li>
          </ul>
          <t>These functions are defined in the following sub-sections.</t>
          <t>In addition, the prover role consists of the following state:</t>
          <ul spacing="normal">
            <li>
              <t>label: Data, a value representing the context in which the proof will be used</t>
            </li>
            <li>
              <t>scalars: [Integer], An ordered set of representation of scalar variables to use in the proof. Each scalar has a label associated with it, stored in a list called <tt>scalar_labels</tt>.</t>
            </li>
            <li>
              <t>elements: [Integer], An ordered set of representation of element variables to use in the proof. Each element has a label associated with it, stored in a list called <tt>element_labels</tt>.</t>
            </li>
            <li>
              <t>constraints: a set of constraints, where each constraint consists of a constraint element and a linear combination of variables.</t>
            </li>
          </ul>
          <section anchor="appendscalar">
            <name>AppendScalar</name>
            <artwork><![CDATA[
AppendScalar(label, assignment)

Inputs:
- label: Data, Scalar variable label
- assignment: Scalar variable

Outputs:
- Integer representation of the new scalar variable

def AppendScalar(label, assignment):
  state.scalars.append(assignment)
  state.scalar_labels.append(label)
  return len(state.scalars) - 1
]]></artwork>
          </section>
          <section anchor="appendelement">
            <name>AppendElement</name>
            <artwork><![CDATA[
AppendElement(label, assignment)

Inputs:
- label: Data, Element variable label
- assignment: Element variable

Outputs:
- Integer representation of the new element variable

def AppendElement(label, assignment):
  state.elements.append(assignment)
  state.element_labels.append(label)
  return len(state.elements) - 1
]]></artwork>
          </section>
          <section anchor="constrain">
            <name>Constrain</name>
            <artwork><![CDATA[
Constrain(result, linearCombination)

Inputs:
- result: Integer, representation of constraint element
- assignment: linear combination of scalar and element variable (representations)

def Constrain(label, linearCombination):
  state.constraints.append((result, linearCombination))
]]></artwork>
          </section>
          <section anchor="prove">
            <name>Prove</name>
            <t>The Prove function is defined below.</t>
            <artwork><![CDATA[
Prove()

Outputs:
- ZKProof, a proof consisting of a challenge Scalar and then fixed number of response Scalar values

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- InvalidVariableAllocationError, raised when the prover was incorrectly configured

def Prove():
  blindings = [G.RandomScalar() for i in range(len(state.scalars))]

  blinded_elements = []
  for (constraint_point, linear_combination) in state.constraints:
    if constraint_point.index > len(state.elements):
      raise InvalidVariableAllocationError

    for (scalar_var, element_var) in linear_combination:
      if scalar_var.index > len(state.scalars):
        raise InvalidVariableAllocationError
      if element_var.index > len(state.elements):
        raise InvalidVariableAllocationError

    scalar_index = linear_combination[0][0]
    element_index = linear_combination[0][1]
    blinded_element = blindings[scalar_index] * state.elements[element_index]

    for i, pair in enumerate(linear_combination):
      if i > 0:
        scalar_index = pair[0]
        element_index = pair[1]
        blinded_element += blindings[scalar_index] * state.elements[element_index]

        blinded_elements.append(blinded_element)

  # Obtain a scalar challenge
  challenge = ComposeChallenge(state.label, state.elements, blinded_elements)

  # Compute response scalars from the challenge, scalars, and blindings.
  responses = []
  for (index, scalar) in enumerate(state.scalars):
    blinding = blindings[index]
    responses.append(blinding - challenge * scalar)

  return ZKProof(challenge, responses)
]]></artwork>
            <t>The function ComposeChallenge is defined below.</t>
            <artwork><![CDATA[
ComposeChallenge(label, elements, blinded_elements)

Inputs:
- label: Data, the proof label
- elements: [Element], ordered list of elements
- blinded_elements: [Element], ordered list of blinded elements

Outputs:
- challenge, Scalar

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

def ComposeChallenge(label, elements, blinded_elements):
  challenge_input = Data() # Empty Data

  for element in elements:
    serialized_element = G.SerializeElement(element)
    challenge_input += I2OSP(len(serialized_element), 2) + serialized_element

  for blinded_element in blinded_elements:
    serialized_blinded_element = G.SerializeElement(blinded_element)
    challenge_input += I2OSP(len(serialized_blinded_element), 2) + serialized_blinded_element

  return G.HashToScalar(challenge_input, label)
]]></artwork>
          </section>
        </section>
        <section anchor="verifier">
          <name>Verifier</name>
          <t>The verifier role consists of four functions:</t>
          <ul spacing="normal">
            <li>
              <t>AppendScalar: This function adds a scalar representation to the transcript.</t>
            </li>
            <li>
              <t>AppendElement: This function adds an element representation to the transcript.</t>
            </li>
            <li>
              <t>Constrain: This function applies an explicit constraint to the proof, where the constraint is expressed as equality between some element and a linear combination of scalar and element representations. An example constraint might be <tt>Z = aX + bY</tt>, for scalars <tt>a</tt>, <tt>b</tt>, and elements
<tt>X</tt>, <tt>Y</tt>, <tt>Z</tt>.</t>
            </li>
            <li>
              <t>Verify: This function applies the Fiat-Shamir heuristic to verify the zero-knowledge proof.</t>
            </li>
          </ul>
          <t>AppendScalar and Verify are defined in the following sub-sections. AppendElement and Constrain matches the functionality used in the prover role.</t>
          <section anchor="appendscalar-1">
            <name>AppendScalar</name>
            <artwork><![CDATA[
AppendScalar(label)

Inputs:
- label: Data, Scalar variable label

Outputs:
- Integer representation of the new scalar variable

def AppendScalar(label):
  state.scalar_labels.append(label)
  return len(state.scalar_labels) - 1
]]></artwork>
          </section>
          <section anchor="verify">
            <name>Verify</name>
            <artwork><![CDATA[
Verify(proof)

Inputs:
- ZKProof, a proof consisting of a challenge Scalar and then fixed number of response Scalar values

Outputs:
- Boolean, True if the proof is valid, False otherwise.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- InvalidVariableAllocationError, raised when the prover was incorrectly configured

def Verify(proof):
  if len(state.elements) != len(state.element_labels):
    raise InvalidVariableAllocationError

  blinded_elements = []
  for (constraint_element, linear_combination) in state.constraints:
    if constraint_element > len(state.elements):
      raise InvalidVariableAllocationError
    for (_, element_var) in linear_combination:
      if element_var > len(state.elements):
        raise InvalidVariableAllocationError

    challenge_element = proof.challenge * state.elements[constraint_element]
    for i, pair in enumerate(linear_combination):
      challenge_element += proof.responses[pair[0]] * state.elements[pair[1]]

    blinded_elements.append(challenge_element)

  challenge = ComposeChallenge(state.label, self.elements, blinded_elements)
  return challenge == proof.challenge
]]></artwork>
          </section>
        </section>
      </section>
      <section anchor="request-proof">
        <name>CredentialRequest Proof</name>
        <t>The request proof is a proof of knowledge of (m1, m2, r1, r2) used to generate the encrypted request. Statements to prove:</t>
        <artwork><![CDATA[
1. m1Enc = m1 * generatorG + r1 * generatorH
2. m2Enc = m2 * generatorG + r2 * generatorH
]]></artwork>
        <section anchor="credentialrequest-proof-creation">
          <name>CredentialRequest Proof Creation</name>
          <artwork><![CDATA[
requestProof = MakeCredentialRequestProof(m1, m2, r1, r2, m1Enc, m2Enc)

Inputs:
- m1: Scalar, first secret.
- m2: Scalar, second secret.
- r1: Scalar, blinding factor for first secret.
- r2: Scalar, blinding factor for second secret.
- m1Enc: Element, first encrypted secret.
- m2Enc: Element, second encrypted secret.

Outputs:
- proof: ZKProof
  - challenge: Scalar, the challenge used in the proof of valid encryption.
  - response0: Scalar, the response corresponding to m1.
  - response1: Scalar, the response corresponding to m2.
  - response2: Scalar, the response corresponding to r1.
  - response3: Scalar, the response corresponding to r2.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()
- contextString: public input

def MakeCredentialRequestProof(m1, m2, r1, r2, m1Enc, m2Enc):
  prover = Prover(contextString + "CredentialRequest")

  m1Var = prover.AppendScalar("m1", m1)
  m2Var = prover.AppendScalar("m2", m2)
  r1Var = prover.AppendScalar("r1", r1)
  r2Var = prover.AppendScalar("r2", r2)

  genGVar = prover.AppendElement("genG", generatorG)
  genHVar = prover.AppendElement("genH", generatorH)
  m1EncVar = prover.AppendElement("m1Enc", m1Enc)
  m2EncVar = prover.AppendElement("m2Enc", m2Enc)

  # 1. m1Enc = m1 * generatorG + r1 * generatorH
  prover.Constrain(m1EncVar, [(m1Var, genGVar), (r1Var, genHVar)])

  # 2. m2Enc = m2 * generatorG + r2 * generatorH
  prover.Constrain(m2EncVar, [(m2Var, genGVar), (r2Var, genHVar)])

  return prover.Prove()
]]></artwork>
        </section>
        <section anchor="credentialrequest-proof-verification">
          <name>CredentialRequest Proof Verification</name>
          <artwork><![CDATA[
validity = VerifyCredentialRequestProof(request)

Inputs:
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.
    - challenge: Scalar, the challenge used in the proof of valid encryption.
    - response0: Scalar, the response corresponding to m1.
    - response1: Scalar, the response corresponding to m2.
    - response2: Scalar, the response corresponding to r1.
    - response3: Scalar, the response corresponding to r2.

Outputs:
- validity: Boolean, True if the proof verifies correctly, False otherwise.

Parameters:
- G: group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()
- contextString: public input

def VerifyCredentialRequestProof(request):
  verifier = Verifier(contextString + "CredentialRequest")

  m1Var = verifier.AppendScalar("m1")
  m2Var = verifier.AppendScalar("m2")
  r1Var = verifier.AppendScalar("r1")
  r2Var = verifier.AppendScalar("r2")

  genGVar = verifier.AppendElement("genG", generatorG)
  genHVar = verifier.AppendElement("genH", generatorH)
  m1EncVar = verifier.AppendElement("m1Enc", request.m1Enc)
  m2EncVar = verifier.AppendElement("m2Enc", request.m2Enc)

  # 1. m1Enc = m1 * generatorG + r1 * generatorH
  verifier.Constrain(m1EncVar, [(m1Var, genGVar), (r1Var, genHVar)])

  # 2. m2Enc = m2 * generatorG + r2 * generatorH
  verifier.Constrain(m2EncVar, [(m2Var, genGVar), (r2Var, genHVar)])

  return verifier.Verify(request.proof)
]]></artwork>
        </section>
      </section>
      <section anchor="response-proof">
        <name>CredentialResponse Proof</name>
        <t>The response proof is a proof of knowledge of (x0, x1, x2, x0Blinding, b) used in the server's CredentialResponse for the client's CredentialRequest. Statements to prove:</t>
        <artwork><![CDATA[
1. X0 = x0 * generatorG + x0Blinding * generatorH
2. X1 = x1 * generatorH
3. X2 = x2 * generatorH
4. X0Aux = b * x0Blinding * generatorH
  4a. HAux = b * generatorH
  4b: X0Aux = x0Blinding * HAux (= b * x0Blinding * generatorH)
5. X1Aux = b * x1 * generatorH
  5a. X1Aux = t1 * generatorH (t1 = b * x1)
  5b. X1Aux = b * X1 (X1 = x1 * generatorH)
6. X2Aux = b * x2 * generatorH
  6a. X2Aux = b * X2 (X2 = x2 * generatorH)
  6b. X2Aux = t2 * generatorH (t2 = b * x2)
7. U = b * generatorG
8. encUPrime = b * (X0 + x1 * Enc(m1) + x2 * Enc(m2))
]]></artwork>
        <section anchor="credentialresponse-proof-creation">
          <name>CredentialResponse Proof Creation</name>
          <artwork><![CDATA[
responseProof = MakeCredentialResponseProof(serverPrivateKey, serverPublicKey, request, b, U, encUPrime, X0Aux, X1Aux, X2Aux, HAux)

Inputs:
- serverPrivateKey:
  - x0: Scalar (private), server private key 0.
  - x1: Scalar (private), server private key 1.
  - x2: Scalar (private), server private key 2.
  - x0Blinding: Scalar (private), blinding value for x0.
- serverPublicKey:
  - X0: Element, server public key 0.
  - X1: Element, server public key 1.
  - X2: Element, server public key 2.
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.
- encUPrime: Element, encrypted UPrime.
- X0Aux: Element, auxiliary point for X0.
- X1Aux: Element, auxiliary point for X1.
- X2Aux: Element, auxiliary point for X2.
- HAux: Element, auxiliary point for generatorH.

Outputs:
- proof: ZKProof
  - challenge: Scalar, the challenge used in the proof of valid response.
  - response0: Scalar, the response corresponding to x0.
  - response1: Scalar, the response corresponding to x1.
  - response2: Scalar, the response corresponding to x2.
  - response3: Scalar, the response corresponding to x0Blinding.
  - response4: Scalar, the response corresponding to b.
  - response5: Scalar, the response corresponding to t1.
  - response6: Scalar, the response corresponding to t2.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()
- contextString: public input

def MakeCredentialResponseProof(serverPrivateKey, serverPublicKey, request, b, U, encUPrime, X0Aux, X1Aux, X2Aux, HAux):
  prover = Prover(contextString + "CredentialResponse")

  x0Var = prover.AppendScalar("x0", serverPrivateKey.x0)
  x1Var = prover.AppendScalar("x1", serverPrivateKey.x1)
  x2Var = prover.AppendScalar("x2", serverPrivateKey.x2)
  x0BlindingVar = prover.AppendScalar("x0Blinding", serverPrivateKey.x0Blinding)
  bVar = prover.AppendScalar("b", b)
  t1Var = prover.AppendScalar("t1", b * serverPrivateKey.x1)
  t2Var = prover.AppendScalar("t2", b * serverPrivateKey.x2)

  genGVar = prover.AppendElement("genG", generatorG)
  genHVar = prover.AppendElement("genH", generatorH)
  m1EncVar = prover.AppendElement("m1Enc", request.m1Enc)
  m2EncVar = prover.AppendElement("m2Enc", request.m2Enc)
  UVar = prover.AppendElement("U", U)
  encUPrimeVar = prover.AppendElement("encUPrime", encUPrime)
  X0Var = prover.AppendElement("X0", serverPublicKey.X0)
  X1Var = prover.AppendElement("X1", serverPublicKey.X1)
  X2Var = prover.AppendElement("X2", serverPublicKey.X2)
  X0AuxVar = prover.AppendElement("X0Aux", X0Aux)
  X1AuxVar = prover.AppendElement("X1Aux", X1Aux)
  X2AuxVar = prover.AppendElement("X2Aux", X2Aux)
  HAuxVar = prover.AppendElement("HAux", HAux)

  # 1. X0 = x0 * generatorG + x0Blinding * generatorH
  prover.Constrain(X0Var, [(x0Var, genGVar), (x0BlindingVar, genHVar)])
  # 2. X1 = x1 * generatorH
  prover.Constrain(X1Var, [(x1Var, genHVar)])
  # 3. X2 = x2 * generatorH
  prover.Constrain(X2Var, [(x2Var, genHVar)])

  # 4. X0Aux = b * x0Blinding * generatorH
  # 4a. HAux = b * generatorH
  prover.Constrain(HAuxVar, [(bVar, genHVar)])
  # 4b: X0Aux = x0Blinding * HAux (= b * x0Blinding * generatorH)
  prover.Constrain(X0AuxVar, [(x0BlindingVar, HAuxVar)])

  # 5. X1Aux = b * x1 * generatorH
  # 5a. X1Aux = t1 * generatorH (t1 = b * x1)
  prover.Constrain(X1AuxVar, [(t1Var, genHVar)])
  # 5b. X1Aux = b * X1 (X1 = x1 * generatorH)
  prover.Constrain(X1AuxVar, [(bVar, X1Var)])

  # 6. X2Aux = b * x2 * generatorH
  # 6a. X2Aux = b * X2 (X2 = x2 * generatorH)
  prover.Constrain(X2AuxVar, [(bVar, X2Var)])
  # 6b. X2Aux = t2 * H (t2 = b * x2)
  prover.Constrain(X2AuxVar, [(t2Var, genHVar)])

  # 7. U = b * generatorG
  prover.Constrain(UVar, [(bVar, genGVar)])
  # 8. encUPrime = b * (X0 + x1 * Enc(m1) + x2 * Enc(m2))
  # simplified: encUPrime = b * X0 + t1 * m1Enc + t2 * m2Enc, since t1 = b * x1 and t2 = b * x2
  prover.Constrain(encUPrimeVar, [(bVar, X0Var), (t1Var, m1EncVar), (t2Var, m2EncVar)])

  return prover.Prove()
]]></artwork>
        </section>
        <section anchor="credentialresponse-proof-verification">
          <name>CredentialResponse Proof Verification</name>
          <artwork><![CDATA[
validity = VerifyCredentialResponseProof(serverPublicKey, response, request)

Inputs:
- serverPublicKey:
  - X0: Element, server public key 0.
  - X1: Element, server public key 1.
  - X2: Element, server public key 2.
- response:
  - U: Element, a randomized generator for the response. `b*G`.
  - encUPrime: Element, encrypted UPrime.
  - X0Aux: Element, auxiliary point for X0.
  - X1Aux: Element, auxiliary point for X1.
  - X2Aux: Element, auxiliary point for X2.
  - HAux: Element, auxiliary point for generatorH.
  - responseProof: ZKProof, a proof of correct generation of U, encUPrime, server public keys, and auxiliary points.
    - challenge: Scalar, the challenge used in the proof of valid response.
    - response0: Scalar, the response corresponding to x0.
    - response1: Scalar, the response corresponding to x1.
    - response2: Scalar, the response corresponding to x2.
    - response3: Scalar, the response corresponding to x0Blinding.
    - response4: Scalar, the response corresponding to b.
    - response5: Scalar, the response corresponding to t1.
    - response6: Scalar, the response corresponding to t2.
- request:
  - m1Enc: Element, first encrypted secret.
  - m2Enc: Element, second encrypted secret.
  - requestProof: ZKProof, a proof of correct generation of m1Enc and m2Enc.

Outputs:
- validity: Boolean, True if the proof verifies correctly, False otherwise.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

def VerifyCredentialResponseProof(serverPublicKey, response, request):
  verifier = Verifier(contextString + "CredentialResponse")

  x0Var = verifier.AppendScalar("x0")
  x1Var = verifier.AppendScalar("x1")
  x2Var = verifier.AppendScalar("x2")
  x0BlindingVar = verifier.AppendScalar("x0Blinding")
  bVar = verifier.AppendScalar("b", b)
  t1Var = verifier.AppendScalar("t1")
  t2Var = verifier.AppendScalar("t2")

  genGVar = verifier.AppendElement("genG", generatorG)
  genHVar = verifier.AppendElement("genH", generatorH)
  m1EncVar = verifier.AppendElement("m1Enc", request.m1Enc)
  m2EncVar = verifier.AppendElement("m2Enc", request.m2Enc)
  UVar = verifier.AppendElement("U", response.U)
  encUPrimeVar = verifier.AppendElement("encUPrime", response.encUPrime)
  X0Var = verifier.AppendElement("X0", serverPublicKey.X0)
  X1Var = verifier.AppendElement("X1", serverPublicKey.X1)
  X2Var = verifier.AppendElement("X2", serverPublicKey.X2)
  X0AuxVar = verifier.AppendElement("X0Aux", response.X0Aux)
  X1AuxVar = verifier.AppendElement("X1Aux", response.X1Aux)
  X2AuxVar = verifier.AppendElement("X2Aux", response.X2Aux)
  HAuxVar = verifier.AppendElement("HAux", response.HAux)

  # 1. X0 = x0 * generatorG + x0Blinding * generatorH
  verifier.Constrain(X0Var, [(x0Var, genGVar), (x0BlindingVar, genHVar)])
  # 2. X1 = x1 * generatorH
  verifier.Constrain(X1Var, [(x1Var, genHVar)])
  # 3. X2 = x2 * generatorH
  verifier.Constrain(X2Var, [(x2Var, genHVar)])

  # 4. X0Aux = b * x0Blinding * generatorH
  # 4a. HAux = b * generatorH
  verifier.Constrain(HAuxVar, [(bVar, genHVar)])
  # 4b: X0Aux = x0Blinding * HAux (= b * x0Blinding * generatorH)
  verifier.Constrain(X0AuxVar, [(x0BlindingVar, HAuxVar)])

  # 5. X1Aux = b * x1 * generatorH
  # 5a. X1Aux = t1 * generatorH (t1 = b * x1)
  verifier.Constrain(X1AuxVar, [(t1Var, genHVar)])
  # 5b. X1Aux = b * X1 (X1 = x1 * generatorH)
  verifier.Constrain(X1AuxVar, [(bVar, X1Var)])

  # 6. X2Aux = b * x2 * generatorH
  # 6a. X2Aux = b * X2 (X2 = x2 * generatorH)
  verifier.Constrain(X2AuxVar, [(bVar, X2Var)])
  # 6b. X2Aux = t2 * H (t2 = b * x2)
  verifier.Constrain(X2AuxVar, [(t2Var, genHVar)])

  # 7. U = b * generatorG
  verifier.Constrain(UVar, [(bVar, genGVar)])
  # 8. encUPrime = b * (X0 + x1 * Enc(m1) + x2 * Enc(m2))
  # simplified: encUPrime = b * X0 + t1 * m1Enc + t2 * m2Enc, since t1 = b * x1 and t2 = b * x2
  verifier.Constrain(encUPrimeVar, [(bVar, X0Var), (t1Var, m1EncVar), (t2Var, m2EncVar)])

  return verifier.Verify(response.proof)
]]></artwork>
        </section>
      </section>
      <section anchor="presentation-proof">
        <name>Presentation Proof</name>
        <t>The presentation proof is a proof of knowledge of (m1, r, z) used in the presentation, and a proof that the nonce used to make the tag is in the range of [0, presentationLimit).</t>
        <t>Statements to prove:</t>
        <artwork><![CDATA[
1. m1Commit = m1 * U + z * generatorH
2. V = z * X1 - r * generatorG
3. G.HashToGroup(presentationContext, "Tag") = m1 * tag + nonce * tag
4. m1Tag = m1 * tag
]]></artwork>
        <section anchor="presentation-proof-creation">
          <name>Presentation Proof Creation</name>
          <artwork><![CDATA[
presentationProof = MakePresentationProof(U, UPrimeCommit, m1Commit, tag, generatorT, credential, V, r, z, nonce, m1Tag)

Inputs:
- U: Element, re-randomized from the U in the response.
- UPrimeCommit: Element, a public key to the MACGGM output UPrime.
- m1Commit: Element, a public key to the client secret (m1).
- tag: Element, the tag element used for enforcing the presentation limit.
- generatorT: Element, used for presentation tag computation.
- credential:
  - m1: Scalar, client's first secret.
  - U: Element, a randomized generator for the response. `b*G`.
  - UPrime: Element, the MAC over the server's private keys and the client's secrets.
  - X1: Element, server public key 1.
- V: Element, a proof helper element.
- r: Scalar (private), a randomly generated element used in presentation.
- z: Scalar (private), a randomly generated element used in presentation.
- nonce: Int, the nonce associated with the presentation.
- m1Tag: Element, helper element for the proof.

Outputs:
- proof: ZKProof
  - challenge: Scalar, the challenge used in the proof of valid presentation.
  - response0: Scalar, the response corresponding to m1.
  - response1: Scalar, the response corresponding to z.
  - response2: Scalar, the response corresponding to -r.
  - response3: Scalar, the response corresponding to nonce.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()
- contextString: public input

def MakePresentationProof(U, UPrimeCommit, m1Commit, tag, generatorT, presentationContext, credential, V, r, z, nonce, m1Tag)
  prover = Prover(contextString + "CredentialPresentation")

  m1Var = prover.AppendScalar("m1", credential.m1)
  zVar = prover.AppendScalar("z", z)
  rNegVar = prover.AppendScalar("-r", -r)
  nonceVar = prover.AppendScalar("nonce", nonce)

  genGVar = prover.AppendElement("genG", generatorG)
  genHVar = prover.AppendElement("genH", generatorH)
  UVar = prover.AppendElement("U", U)
  _ = prover.AppendElement("UPrimeCommit", UPrimeCommit)
  m1CommitVar = prover.AppendElement("m1Commit", m1Commit)
  VVar = prover.AppendElement("V", V)
  X1Var = prover.AppendElement("X1", credential.X1)
  tagVar = prover.AppendElement("tag", tag)
  genTVar = prover.AppendElement("genT", generatorT)
  m1TagVar = prover.AppendElement("m1Tag", m1Tag)

  # 1. m1Commit = m1 * U + z * generatorH
  prover.Constrain(m1CommitVar, [(m1Var, UVar), (zVar, genHVar)])
  # 2. V = z * X1 - r * generatorG
  prover.Constrain(VVar, [(zVar, X1Var), (rNegVar, genGVar)])
  # 3. G.HashToGroup(presentationContext, "Tag") = m1 * tag + nonce * tag
  prover.Constrain(genTVar, [(m1Var, tagVar), (nonceVar, tagVar)])
  # 4. m1Tag = m1 * tag
  prover.Constrain(m1TagVar, [(m1Var, tagVar)])

  return prover.Prove()
]]></artwork>
        </section>
        <section anchor="presentation-proof-verification">
          <name>Presentation Proof Verification</name>
          <artwork><![CDATA[
validity = VerifyPresentationProof(
  serverPrivateKey,
  serverPublicKey,
  requestContext,
  presentationContext,
  presentation,
  m1Tag)

Inputs:
- serverPrivateKey:
  - x0: Scalar (private), server private key 0.
  - x1: Scalar (private), server private key 1.
  - x2: Scalar (private), server private key 2.
  - x0Blinding: Scalar (private), blinding value for x0.
- serverPublicKey:
  - X0: Element, server public key 0.
  - X1: Element, server public key 1.
  - X2: Element, server public key 2.
- requestContext: Data, context for the credential request.
- presentationContext: Data (public), used for presentation tag computation.
- presentation:
  - U: Element, re-randomized from the U in the response.
  - UPrimeCommit: Element, a public key to the issued UPrime.
  - m1Commit: Element, a public key to the client secret (m1).
  - tag: Element, the tag element used for enforcing the presentation limit.
  - presentationProof: ZKProof, a proof of correct generation of the presentation.
    - challenge: Scalar, the challenge used in the proof of valid presentation.
    - response0: Scalar, the response corresponding to m1.
    - response1: Scalar, the response corresponding to z.
    - response2: Scalar, the response corresponding to -r.
    - response3: Scalar, the response corresponding to nonce.
- m1Tag: Element, helper to validate the presentation proof.

Outputs:
- validity: Boolean, True if the proof verifies correctly, False otherwise.

Parameters:
- G: Group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()
- contextString: public input

def VerifyPresentationProof(
  serverPrivateKey,
  serverPublicKey,
  requestContext,
  presentationContext,
  presentation,
  m1Tag):

  m2 = G.HashToScalar(requestContext, "requestContext")
  V = serverPrivateKey.x0 * presentation.U + serverPrivateKey.x1 * presentation.m1Commit + serverPrivateKey.x2 * m2 * presentation.U - presentation.UPrimeCommit
  generatorT = G.HashToGroup(presentationContext, "Tag")

  verifier = Verifier(contextString + "CredentialPresentation")

  m1Var = verifier.AppendScalar("m1")
  zVar = verifier.AppendScalar("z")
  rNegVar = verifier.AppendScalar("-r")
  nonceVar = verifier.AppendScalar("nonce")

  genGVar = verifier.AppendElement("genG", generatorG)
  genHVar = verifier.AppendElement("genH", generatorH)
  UVar = verifier.AppendElement("U", presentation.U)
  _ = verifier.AppendElement("UPrimeCommit", presentation.UPrimeCommit)
  m1CommitVar = verifier.AppendElement("m1Commit", presentation.m1Commit)
  VVar = verifier.AppendElement("V", presentation.V)
  X1Var = verifier.AppendElement("X1", serverPublicKey.X1)
  tagVar = prover.AppendElement("tag", presentation.tag)
  genTVar = verifier.AppendElement("genT", generatorT)
  m1TagVar = prover.AppendElement("m1Tag", m1Tag)

  # 1. m1Commit = m1 * U + z * generatorH
  verifier.Constrain(m1CommitVar, [(m1Var, UVar), (zVar, genHVar)])
  # 2. V = z * X1 - r * generatorG
  verifier.Constrain(VVar, [(zVar, X1Var), (rNegVar, genGVar)])
  # 3. G.HashToGroup(presentationContext, "Tag") = m1 * tag + nonceVar * tag
  verifier.Constrain(genTVar, [(m1Var, tagVar), (nonceVar, tagVar)])
  # 4. m1Tag = m1 * tag
  prover.Constrain(m1TagVar, [(m1Var, tagVar)])

  return verifier.Verify(presentation.proof)
]]></artwork>
        </section>
      </section>
      <section anchor="range-proof-for-arbitrary-values">
        <name>Range Proof for Arbitrary Values</name>
        <t>This section specifies a range proof in the framework of
<xref target="SIGMA"/> to prove a secret value <tt>v</tt> lies
in an arbitrary interval <tt>[0,upper_bound)</tt>. Before specifying the proof system, we first
give a brief overview of how it works. For simplicity, assume that <tt>upper_bound</tt> is a
power of two, that is, <tt>upper_bound == 2^k</tt> for some <tt>k</tt>.</t>
        <t>To prove a value lies in <tt>[0,(2^k)-1)</tt>, we prove it has a valid <tt>k</tt>-bit representation.
This is proven by committing to the full value <tt>v</tt>, then all bits of the bit decomposition
<tt>b</tt> of the value <tt>v</tt>, and then proving each coefficient of the bit decomposition is
actually <tt>0</tt> or <tt>1</tt> and that the sum of the bits amounts to the full value <tt>v</tt>.  This involves the following steps:</t>
        <ol spacing="normal" type="1"><li>
            <t>Commit to the bits of <tt>v</tt>. That is, for each bit <tt>b[i]</tt> of the bit decomposition of <tt>v</tt>, let
<tt>D[i] = b[i] * generatorG + s[i] * generatorH</tt>, where <tt>s[i]</tt> is a blinding scalar.</t>
          </li>
          <li>
            <t>Prove that <tt>b[i]</tt> is in <tt>{0,1}</tt> by computing proving the algebraic relation <tt>b[i] *
(b[i]-1) == 0</tt> holds. This quadratic relation can be linearized by
adding an auxilary witness <tt>s2[i]</tt> and adding the linear relation
<tt>D[i] == b[i] * D[i] + s2[i] * generatorH</tt> to the equation system. A valid witness <tt>s2[i]</tt> can only
be computed by the prover if <tt>b[i]</tt> is in <tt>{0,1}</tt>. Successfully computing a witness for
any other value requires the prover to break the discrete logarithm problem.</t>
          </li>
          <li>
            <t>Having verified the proof the above relation, the verifier checks the sum by computing</t>
          </li>
        </ol>
        <artwork><![CDATA[
C == D[0] * 2^0 + D[1] * 2^1 + D[2] * 2^2 + ... + D[k-1] * 2^{k-1}
]]></artwork>
        <t>The third step is verified outside of the proof by adding the commitments
homomorphically.</t>
        <t>To support the general case, where <tt>upper_bound</tt> is not necessarily a power of two,
we extend the range proof for arbitrary ranges by decomposing the range
up to the second highest power of two and adding an additional, non-binary range that
covers the remaining range. This is detailed in <tt>ComputeBases</tt> below.</t>
        <artwork><![CDATA[
def ComputeBases(upper_bound):

Inputs:

- upper_bound: the maximum value of the range (exclusive), as integer.

Outputs:

- bases: an array of Scalar bases to represent elements, sorted in descending order. A base is
  either a power of two or a unique remainder that can be used to represent any integer
  in [0, upper_bound).

# compute bases to express the commitment as a linear combination of the bit decomposition
remainder=upper_bound
bases=[]
# Generate all but the last power-of-two base.
for i in range(ceil(log2(upper_bound)) - 1):
    base = 2 ** i
    remainder -= base
    bases.append((G.Scalar(base))
bases.append(remainder - 1)

# call sorted on array to ensure the additional base is in correct order
return sorted(bases, reverse=True)
]]></artwork>
        <t>Using the bases from <tt>ComputeBases</tt>, the function <tt>ComputeStatementAndWitnesses</tt>
represents the secret value <tt>v</tt> as a linear combination of the bases, using the resulting
bit representation to generate the cryptographic commitments and witness values for the
range proof.</t>
        <artwork><![CDATA[
def ComputeStatementAndWitnesses(v, upper_bound):

Inputs:

- v: the scalar we want to prove is in range [0, upper_bound)
- r: randomness for commitment to v
- upper_bound: the maximum integer value of the range

Outputs:

- statement: proof statement for the relation
- [s,s2]: the witness for the equations appended to the statement (the bit
  decomposition, the secret shares of r, and the auxiliary witness s2. Each s2[i] is either zero when
b[i] is set) or s[i] when b[i] is zero.
- C: the commitment to v
- D: the commitments to the bit decomposition of v

Parameters:
- G: group
- generatorG: Element, equivalent to G.GeneratorG()
- generatorH: Element, equivalent to G.GeneratorH()

Exceptions:
- NumberTooBigError, raised when v is out of range

if G.ScalarToInt(v) >= upper_bound:
    raise NumberTooBigError

bases = ComputeBases(upper_bound)

# Compute bit decomposition of v.
b = []
v_remainder = G.ScalarToInt(v)
for base in bases:
    # Implementation note: In order to avoid leaking v via a timing channel, this code should be written to be constant time.
    if v_remainder >= base:
        v_remainder -= G.ScalarToInt(base)
        b.append(G.Scalar(1))
    else:
        b.append(G.Scalar(0))

# array of group elements where the i-th element corresponds to b[i] * generatorG + s * generatorH
D = []
# blinding elements for Pedersen commitment, secret shares of r
s = []
# complementing blinders for proof of bit-ness
s2 = []
partial_sum = G.Scalar(0)
for i in range(len(bases) - 1):
    s.append(G.random_scalar())
    partial_sum += bases[i] * s[i]
    s2.append((G.Scalar(1) - b[i]) * s[i])
    D.append(b[i] * generatorG + s[i] * generatorH)
idx = len(bases) - 1
s[idx] = r - partial_sum
s2.append((G.Scalar(1) - b[idx]) * s[idx])
D.append(b[idx] * generatorG + s[idx] * generatorH)

# Compute the Pedersen commitment to the full value of v, using the provided r.
C = v * generatorG + r * generatorH

# start computing the linear relation
statement = LinearRelation(G)

[var_G, var_H, var_C] = statement.allocate_elements(3)

# allocate variables for decomposed statements
vars_b = statement.allocate_scalars(len(b))
# allocate blinding elements for Pedersen commitment
vars_s = statement.allocateScalars(len(b))
# allocate complementing blinders for proof of bit-ness
vars_s2 = statement.allocateScalars(len(b))
# allocate bit commitment values
vars_D = statement.allocateElements(len(b))

# Add equations proving each b[i] is in {0,1}
# For each base, we prove:
#   D[i] = b[i] * generatorG + s[i] * generatorH      (b[i] is committed in D[i])
#   b[i] * (b[i] - 1) = 0       (b[i] is 0 or 1)
for i in range(len(b)):
        statement.set_elements([(vars_D[i], D[i])])
        # add Pedersen commitment to the ith bit.
        statement.append_equation(vars_D[i], [(vars_b[i], var_G), (vars_s[i], var_H)])
        # add statement that b[i] is in {0,1}
        statement.append_equation(vars_D[i], [(vars_b[i], vars_D[i]), (vars_s2[i], var_H)])

return (statement, [r, v, b, s, s2], [C,D])
]]></artwork>
      </section>
    </section>
    <section anchor="ciphersuites">
      <name>Ciphersuites</name>
      <t>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.</t>
      <t>A ciphersuite contains an instantiation of the following functionality:</t>
      <ul spacing="normal">
        <li>
          <t><tt>Group</tt>: A prime-order Group exposing the API detailed in <xref target="pog"/>, 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 <xref section="3.1" sectionFormat="comma" target="I-D.irtf-cfrg-hash-to-curve"/>.
For HashToScalar, each group specifies an integer order that is used in
reducing integer values to a member of the corresponding scalar field.</t>
        </li>
      </ul>
      <t>This section includes an initial set of ciphersuites with supported groups.
It also includes implementation details for each ciphersuite, focusing on input validation.</t>
      <section anchor="arcp-256">
        <name>ARC(P-256)</name>
        <t>This ciphersuite uses P-256 <xref target="NISTCurves"/> for the Group.
The value of the ciphersuite identifier is "P256". The value of
contextString is "ARCV1-P256".</t>
        <ul spacing="normal">
          <li>
            <t>Group: P-256 (secp256r1) <xref target="NISTCurves"/>
            </t>
            <ul spacing="normal">
              <li>
                <t>Order(): Return 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551.</t>
              </li>
              <li>
                <t>Identity(): As defined in <xref target="NISTCurves"/>.</t>
              </li>
              <li>
                <t>Generator(): As defined in <xref target="NISTCurves"/>.</t>
              </li>
              <li>
                <t>RandomScalar(): Implemented by returning a uniformly random Scalar in the range
[1, <tt>G.Order()</tt> - 1]. Refer to <xref target="random-scalar"/> for implementation guidance.</t>
              </li>
              <li>
                <t>HashToGroup(x, info): Use hash_to_curve with suite P256_XMD:SHA-256_SSWU_RO_
<xref target="I-D.irtf-cfrg-hash-to-curve"/>, input <tt>x</tt>, and DST =
"HashToGroup-" || contextString || info.</t>
              </li>
              <li>
                <t>HashToScalar(x, info): Use hash_to_field from <xref target="I-D.irtf-cfrg-hash-to-curve"/>
using L = 48, <tt>expand_message_xmd</tt> with SHA-256, input <tt>x</tt> and
DST = "HashToScalar-" || contextString || info, and
prime modulus equal to <tt>Group.Order()</tt>.</t>
              </li>
              <li>
                <t>ScalarInverse(s): Returns the multiplicative inverse of input Scalar <tt>s</tt> mod <tt>Group.Order()</tt>.</t>
              </li>
              <li>
                <t>SerializeElement(A): Implemented using the compressed Elliptic-Curve-Point-to-Octet-String
method according to <xref target="SEC1"/>; Ne = 33.</t>
              </li>
              <li>
                <t>DeserializeElement(buf): Implemented by attempting to deserialize a 33-byte array to
a public key using the compressed Octet-String-to-Elliptic-Curve-Point method according to <xref target="SEC1"/>,
and then performs partial public-key validation as defined in section 5.6.2.3.4 of
<xref target="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.</t>
              </li>
              <li>
                <t>SerializeScalar(s): Implemented using the Field-Element-to-Octet-String conversion
according to <xref target="SEC1"/>; Ns = 32.</t>
              </li>
              <li>
                <t>DeserializeScalar(buf): Implemented by attempting to deserialize a Scalar from a 32-byte
string using Octet-String-to-Field-Element from <xref target="SEC1"/>. This function can fail if the
input does not represent a Scalar in the range [0, <tt>G.Order()</tt> - 1].</t>
              </li>
            </ul>
          </li>
        </ul>
      </section>
      <section anchor="random-scalar">
        <name>Random Scalar Generation</name>
        <t>Two popular algorithms for generating a random integer uniformly distributed in
the range [1, G.Order() -1] are as follows:</t>
        <section anchor="rejection-sampling">
          <name>Rejection Sampling</name>
          <t>Generate a random byte array with <tt>Ns</tt> bytes, and attempt to map to a Scalar
by calling <tt>DeserializeScalar</tt> in constant time. If it succeeds and is non-zero,
return the result. Otherwise, try again with another random byte array, until the
procedure succeeds. Failure to implement <tt>DeserializeScalar</tt> in constant time
can leak information about the underlying corresponding Scalar.</t>
          <t>As an optimization, if the group order is very close to a power of
2, it is acceptable to omit the rejection test completely.  In
particular, if the group order is p, and there is an integer b
such that |p - 2<sup>b</sup>| is less than 2<sup>(b/2)</sup>, then
<tt>RandomScalar</tt> can simply return a uniformly random integer of at
most b bits.</t>
        </section>
        <section anchor="random-number-generation-using-extra-random-bits">
          <name>Random Number Generation Using Extra Random Bits</name>
          <t>Generate a random byte array with <tt>L = ceil(((3 * ceil(log2(G.Order()))) / 2) / 8)</tt>
bytes, and interpret it as an integer; reduce the integer modulo <tt>G.Order()</tt> and return the
result. See <xref section="5" sectionFormat="comma" target="I-D.irtf-cfrg-hash-to-curve"/> for the underlying derivation of <tt>L</tt>.</t>
        </section>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>For arguments about correctness, unforgeability, anonymity, and blind issuance of the ARC protocol, see the
"Formal Security Definitions for Keyed-Verification Anonymous Credentials" in <xref target="KVAC"/>.</t>
      <t>This section elaborates on unlinkability properties for ARC and other implementation details
necessary for these properties to hold.</t>
      <section anchor="credential-request-unlinkability">
        <name>Credential Request Unlinkability</name>
        <t>Client credential requests are constructed such that the server cannot distinguish between any two credential requests from the same client and two requests from different clients. We refer to this property as issuance unlinkability. This property is achieved by the way the credential requests are constructed. In particular, each credential request consists of two Pedersen commitments with fresh blinding factors, which are used to commit to a freshly generated client secret and request context. The resulting request is therefore statistically hiding, and independent from other requests from the same client. More details about this unlinkability property can be found in <xref target="KVAC"/> and <xref target="REVISITING_KVAC"/>.</t>
      </section>
      <section anchor="credential-issuance-unlinkability">
        <name>Credential Issuance Unlinkability</name>
        <t>The server commitment to <tt>x0</tt> is defined as <tt>X0 = x0 * G.generatorG() + x0Blinding * G.GeneratorH()</tt>, following the definitions in <xref target="KVAC"/>. This is computationally binding to the secret key <tt>x0</tt>. This means that unless the discrete log is broken, the credentials issued under one server commitment <tt>X0, X1, ...</tt> will all be issued under the same private keys <tt>x0, x1, ...</tt></t>
        <t>However, an adversary breaking the discrete log (e.g., a quantum adversary) can find pairs <tt>(x0, x0Blinding)</tt> and <tt>(x0', x0Blinding')</tt> both committing to <tt>X0</tt> and use them to issue different credentials. This capability would let the adversary partitioning the client anonymity set by linking clients to the underlying secret used for credential issuance, i.e., <tt>x0</tt> or <tt>x0'</tt>. This requires an active attack and therefore is not an immediate concern.</t>
        <t>Statistical anonymity is possible by committing to <tt>x0</tt> and x0Blinding` separately, as in <xref target="REVISITING_KVAC"/>. However, the security of this construction requires additional analysis.</t>
      </section>
      <section anchor="pres-unlinkability">
        <name>Presentation Unlinkability</name>
        <t>Client credential presentations are constructed so that all presentations are indistinguishable, even if coming from the same user. We refer to this property as presentation unlinkability. This property is achieved by the way the credential presentations are constructed. The presentation elements <tt>[U, UPrimeCommit, m1Commit]</tt> are indistinguishable from all other presentations made from credentials issued with the same server keys, as detailed in <xref target="KVAC"/>.</t>
        <t>The indistinguishability set for these presentation elements is <tt>sum_{i=0}^c(p_i)</tt>, where <tt>c</tt> is the number of credentials issued with the same server keys, and <tt>p_i</tt> is the number of presentations made for each of those credentials.</t>
        <t>The presentation elements <tt>[tag, nonce, presentationContext, presentationProof]</tt> are indistinguishable from all presentations made from credentials issued with the same server keys for that presentationContext, with the exception of presentations with the same nonce (since those presentations can be ascertained as being generated from different credentials, as long as the presentation tag is unique).</t>
        <t>The indistinguishability set for those presentation elements is <tt>sum_{i=0}^c(p_i[presentationContext]) - k[presentationContext]</tt>, where <tt>c</tt> is the number of credentials issued with the same server keys, <tt>p_i[presentationContext]</tt> is the number of presentations made for each of those credentials with the same presentationContext, and <tt>k</tt> is the number of presentations with the same nonce for that presentationContext. As long as the nonces are generated randomly from the range defined by the presentation limit, <tt>k[presentationContext]</tt> should be roughly equal to <tt>sum_{i=0}^c(p_i[presentationContext]) / n</tt>, where <tt>n</tt> is the presentation limit. Therefore, the indistinguishability set can be represented as <tt>sum_{i=0}^c(p_i[presentationContext])(1 - 1/n)</tt>, where a larger presentation limit results in a larger indistinguishability set and therefore stronger unlinkability properties.</t>
        <t>OPEN ISSUE: hide the nonce and replace the tag proof with a range proof built from something like Bulletproofs.</t>
      </section>
      <section anchor="timing-leaks">
        <name>Timing Leaks</name>
        <t>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 proof generation and verification.</t>
      </section>
    </section>
    <section anchor="alternatives-considered">
      <name>Alternatives considered</name>
      <t>ARC uses the MACGGM algebraic MAC as its underlying primitive, as detailed in <xref target="KVAC"/> and <xref target="REVISITING_KVAC"/>. This offers the benefit of having a lower credential size than MACDDH, which is an alternative algebraic MAC detailed in <xref target="KVAC"/>.</t>
      <t>The BBS anonymous credential scheme, as detailed in <xref target="BBS"/> and its variants, is efficient and publicly verifiable, but requires pairings for verification. This is problematic for adoption because pairings are not supported as widely in software and hardware as non-pairing elliptic curves.</t>
      <t>It is possible to construct a keyed-verification variant of BBS which doesn't use pairings, as discussed in <xref target="BBDT17"/> and <xref target="REVISITING_KVAC"/>. However these keyed-verification BBS variants require more analysis, proofs of security properties, and review to be considered mature enough for safe deployment.</t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <t>This document has no IANA actions.</t>
    </section>
    <section anchor="test-vectors">
      <name>Test Vectors</name>
      <t>This section contains test vectors for the ARC ciphersuites specified in this document.</t>
      <section anchor="arcv1-p256">
        <name>ARCV1-P256</name>
        <artwork><![CDATA[
// ServerKey
x0 = 3338fa65ec36e0290022b48eb562889d89dbfa691d1cde91517fa222ed7ad36
4
x1 = f9db001266677f62c095021db018cd8cbb55941d4073698ce45c405d1348b7b
1
x2 = 350e8040f828bf6ceca27405420cdf3d63cb3aef005f40ba51943c802687796
3
xb = fd293126bb49a6d793cd77d7db960f5692fec3b7ec07602c60cd32aee595dff
d
X0 = 0232b5e93dc2ff489c20a986a84757c5cc4512f057e1ea92011a26d3ad2c562
88d
X1 = 03c413230a9bd956718aa46138a33f774f4c708d61c1d6400d404243049d4a3
1dc
X2 = 02db00f6f8e6d235786a120017bd356fe1c9d09069d3ac9352cc9be10ef1505
a55

// CredentialRequest
Blinding_0 = 0000000000000000000000000000000000000000000000000000000
000000001
Blinding_1 = 0000000000000000000000000000000000000000000000000000000
000000002
Blinding_2 = 0000000000000000000000000000000000000000000000000000000
000000003
Blinding_3 = 0000000000000000000000000000000000000000000000000000000
000000004
request_context = 74657374207265717565737420636f6e74657874
m1 = eedfe7939e2382934ab5b0f76aae44124955d2c5ebf9b41d88786259c34692d
2
m2 = 911fb315257d9ae29d47ecb48c6fa27074dee6860a0489f8db6ac9a486be6a3
e
r1 = 008035081690bfde3b1e68b91443c22cc791d244340fe957d5aa44d7313740d
f
r2 = d59c5e6ff560cc597c2b8ca25256c720bceca2ab03921492c5e9e4ad3b55800
2
m1_enc = 03b8f11506a5302424143573e087fa20195cb5e893a67ef354eae3a78e2
63c54e4
m2_enc = 03f1ae4d7b78ba8030bd63859d4f4a909395c52bda34716b6620a2fdd52
b336fc9
proof = 0f361327abbc724ff0d37db365065bc4bd60e18125842bb4c03a7e5a632a
1e95e74dcc440fcb9fb39106922e0d2544e6c82ca710abf35e8b10bf5d61296c9adb
7d683eaed9a76a755b73f2b4b6e763a7c7883ce4b5c21bd02cd96b9af18cfb227f1a
cb4ead77c85049d291ed7841405610843f163e9cc2f6a8869111582324cd32bf1300
0c129d274ccf5386cb90e839916d5dff7eade18e3eabec415f613911

// CredentialResponse
Blinding_0 = 0000000000000000000000000000000000000000000000000000000
000000001
Blinding_1 = 0000000000000000000000000000000000000000000000000000000
000000002
Blinding_2 = 0000000000000000000000000000000000000000000000000000000
000000003
Blinding_3 = 0000000000000000000000000000000000000000000000000000000
000000004
Blinding_4 = 0000000000000000000000000000000000000000000000000000000
000000005
Blinding_5 = 0000000000000000000000000000000000000000000000000000000
000000006
Blinding_6 = 0000000000000000000000000000000000000000000000000000000
000000007
b = e699140babbe599f7dd8f6e3e8f615e5f201d1c2b0bc2f821f19e80a0a0e1e7b
U = 033ee1ebbcff622bc26b10932ed1eb147226d832048fb2337dc0ad7722cb0748
3d
enc_U_prime = 035b8e09ce8776f1a2c7ef8610c9a6a39936c5666ab8b28d6629d3
685056716482
X0_aux = 02d453c121324114367906bd11ffc3b6e6a77b75382497279b1a60ab841
2c1dec6
X1_aux = 03b0e4b1f376c6207bf34efda46ce54b132a20b90bc28b9152f3e441fe2
b508b63
X2_aux = 0327369efcb7577abaeb7b56940e6e042126900bdf8bd8944c0adbb7be3
ad98e2a
H_aux = 03d3cd09eeb8d19716586a49260c69309c495a717a36cad3381f6c02ac80
b70e64
proof = dd4596175db0b4273fcdff330370d2b5e7a4bf92bf518141f4553af37ef0
e1260cb8312affc2462800adba102117448b449985d1704d8afd0df9ac708231561d
ca56faae325cb56b0a9e8ad07bdc6ce90f6e7430090e970a7240e289218de7a17672
bea9a66187d102ffef976fb01af69d8d3aa3156a5a4223dc6d08b8ce9f1d2639a2ed
c7052404bf1410adf6c41465bd687e3dfa5372ea71f804b56d947bae9482e5707f42
dbe35f8b0e11b4a0d27a5a01e1b9a75b66d82b7945eb0b002ee400bebcdc4c3133f8
04b22bd2d771762058cc35a5033365d2e15150fe46d3b0e98e18ee55f0451b0b1714
20f73592292e4ff50603c1f0d7769dbd090936090f63

// Credential
m1 = eedfe7939e2382934ab5b0f76aae44124955d2c5ebf9b41d88786259c34692d
2
U = 033ee1ebbcff622bc26b10932ed1eb147226d832048fb2337dc0ad7722cb0748
3d
U_prime = 02637fe04cc143281ee607bd8f898e670293dce44a2840b9cbb9e0d1fc
7a2b29b4
X1 = 03c413230a9bd956718aa46138a33f774f4c708d61c1d6400d404243049d4a3
1dc

// Presentation1
Blinding_0 = 0000000000000000000000000000000000000000000000000000000
000000001
Blinding_1 = 0000000000000000000000000000000000000000000000000000000
000000002
Blinding_2 = 0000000000000000000000000000000000000000000000000000000
000000003
Blinding_3 = 0000000000000000000000000000000000000000000000000000000
000000004
presentation_context = 746573742070726573656e746174696f6e20636f6e746
57874
a = b78e57df8f0a95d102ff12bbb97e15ed35c23e54f9b4483d30b76772ee60d886
r = 42252210dd60ddbbf1a57e3b144e26dd693b7644a9626a8c36896ede53d12930
z = f5a4bbcf14e55e357df9f5ccb5ded37b2b14bc2e1a68e31f86416f0606ee75d1
U = 032704f22133d2ec70f9e6f4bbf64c582220b666f2e2c1d37c3f8995a2a5568c
7e
U_prime_commit = 03533cf1b2fd53a0716e02425eb42e4c55835aa6b2992d364cb
a70810d0f8aeb51
m1_commit = 03e412408579105213ed10b6447c85bcd672ba73ecae1e21c463d0df
4ef7beb814
nonce = 0x0
tag = 031a774fd87a8f18f6420bea43cf5425e7426eec8ba7b8df5c13dc05f10ec6
52d9
proof = a558da5f17c04adcb0898827aaded14be1dc612dcd12b0579c11bb387ce9
ae4b7dbcb3bbe413caaaf754d99e5a342abb7e0041458d670f4b58eda37e745a6752
95d7a7b86248141d6547b53d793e5c77896ec4dc8dd438ab66d9c8b43ef6b060938a
1ca793057b154970ebc3c7ec3a23134e0852d0041f9098ce77311e5b5eca00000000
00000000000000000000000000000000000000000000000000000004

// Presentation2
Blinding_0 = 0000000000000000000000000000000000000000000000000000000
000000001
Blinding_1 = 0000000000000000000000000000000000000000000000000000000
000000002
Blinding_2 = 0000000000000000000000000000000000000000000000000000000
000000003
Blinding_3 = 0000000000000000000000000000000000000000000000000000000
000000004
presentation_context = 746573742070726573656e746174696f6e20636f6e746
57874
a = 95bcf45150a61f5c44a6cfbf343cd9e0f593f127b6f49bec0f9b20f0550504a2
r = d7ed72750b6d366ed0febdc539b52d89434f468a578c59d7ca9015b7da240ad6
z = 91eedfb168c556ff5ca3b89d047f482c9279b47f584aab6c7f895f7674251771
U = 035fd233dee2c147155c6008ea64941b6ff7b315aced12531468f2e27bf22e3e
f0
U_prime_commit = 02434af337b87fd21d1e3d950aebfc8033a3d2e9dd2bb8b9e79
53488078754496d
m1_commit = 02a578fd3a84eb5b657367b02de39b45fd48ab7781ef8f94efe60127
4a5ded2a07
nonce = 0x1
tag = 03084fe6fff0ecc7c33ef5c49b492dda38083f52e9a2b70b88f3d4b4ba7b50
afba
proof = 050965cde906fc4723333b100ce0fd9f7b026315f1db16984d4cccb2bc4a
a65eb7a17f5b8dfe4f14d40006506ee5fb323e829dd4cb9dc3c455b2e04dd691600a
ec3cc3f1939198a80acb78b7f90b3bff769cab890f33e4d69b7c302d21ad35ec457d
048d3ed7d13ee82c3c0aac2129ad0c8375cf29cd8ea3948a16b9247b1cc5faf69a31
16f903b9dcccc4eff31f026041e49797b53c87eca66cfe1040187ef7

]]></artwork>
      </section>
    </section>
    <section anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The authors would like to acknowledge helpful conversations with Tommy Pauly about rate limiting and Privacy Pass integration.</t>
    </section>
  </middle>
  <back>
    <references anchor="sec-combined-references">
      <name>References</name>
      <references anchor="sec-normative-references">
        <name>Normative References</name>
        <reference anchor="RFC8017">
          <front>
            <title>PKCS #1: RSA Cryptography Specifications Version 2.2</title>
            <author fullname="K. Moriarty" initials="K." role="editor" surname="Moriarty"/>
            <author fullname="B. Kaliski" initials="B." surname="Kaliski"/>
            <author fullname="J. Jonsson" initials="J." surname="Jonsson"/>
            <author fullname="A. Rusch" initials="A." surname="Rusch"/>
            <date month="November" year="2016"/>
            <abstract>
              <t>This document provides recommendations for the implementation of public-key cryptography based on the RSA algorithm, covering cryptographic primitives, encryption schemes, signature schemes with appendix, and ASN.1 syntax for representing keys and for identifying the schemes.</t>
              <t>This document represents a republication of PKCS #1 v2.2 from RSA Laboratories' Public-Key Cryptography Standards (PKCS) series. By publishing this RFC, change control is transferred to the IETF.</t>
              <t>This document also obsoletes RFC 3447.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="8017"/>
          <seriesInfo name="DOI" value="10.17487/RFC8017"/>
        </reference>
        <reference anchor="I-D.irtf-cfrg-hash-to-curve">
          <front>
            <title>Hashing to Elliptic Curves</title>
            <author fullname="Armando Faz-Hernandez" initials="A. F." surname="Faz-Hernandez">
              <organization>Cloudflare, Inc.</organization>
            </author>
            <author fullname="Sam Scott" initials="S." surname="Scott">
              <organization>Cornell Tech</organization>
            </author>
            <author fullname="Nick Sullivan" initials="N." surname="Sullivan">
              <organization>Cloudflare, Inc.</organization>
            </author>
            <author fullname="Riad S. Wahby" initials="R. S." surname="Wahby">
              <organization>Stanford University</organization>
            </author>
            <author fullname="Christopher A. Wood" initials="C. A." surname="Wood">
              <organization>Cloudflare, Inc.</organization>
            </author>
            <date day="15" month="June" year="2022"/>
            <abstract>
              <t>This document specifies a number of algorithms for encoding or hashing an arbitrary string to a point on an elliptic curve.  This document is a product of the Crypto Forum Research Group (CFRG) in the IRTF.
              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-hash-to-curve-16"/>
        </reference>
        <reference anchor="SIGMA">
          <front>
            <title>Interactive Sigma Proofs</title>
            <author fullname="Michele Orrù" initials="M." surname="Orrù">
              <organization>CNRS</organization>
            </author>
            <author fullname="Cathie Yun" initials="C." surname="Yun">
              <organization>Apple, Inc.</organization>
            </author>
            <date day="8" month="August" year="2025"/>
            <abstract>
              <t>   This document describes interactive sigma protocols, a class of
   secure, general-purpose zero-knowledge proofs of knowledge consisting
   of three moves: commitment, challenge, and response.  Concretely, the
   protocol allows one to prove knowledge of a secret witness without
   revealing any information about it.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-sigma-protocols-00"/>
        </reference>
        <reference anchor="KEYAGREEMENT">
          <front>
            <title>Recommendation for pair-wise key-establishment schemes using discrete logarithm cryptography</title>
            <author fullname="Elaine Barker" initials="E." surname="Barker">
              <organization/>
            </author>
            <author fullname="Lily Chen" initials="L." surname="Chen">
              <organization/>
            </author>
            <author fullname="Allen Roginsky" initials="A." surname="Roginsky">
              <organization/>
            </author>
            <author fullname="Apostol Vassilev" initials="A." surname="Vassilev">
              <organization/>
            </author>
            <author fullname="Richard Davis" initials="R." surname="Davis">
              <organization/>
            </author>
            <date month="April" year="2018"/>
          </front>
          <seriesInfo name="DOI" value="10.6028/nist.sp.800-56ar3"/>
          <refcontent>National Institute of Standards and Technology</refcontent>
        </reference>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="KVAC" target="https://eprint.iacr.org/2013/516">
          <front>
            <title>Keyed-Verification Anonymous Credentials from Algebraic MACs</title>
            <author>
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="REVISITING_KVAC" target="https://eprint.iacr.org/2024/1552">
          <front>
            <title>Revisiting Keyed-Verification Anonymous Credentials</title>
            <author>
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="BBS" target="https://eprint.iacr.org/2004/174">
          <front>
            <title>Short Group Signatures</title>
            <author>
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="BBDT17" target="https://link.springer.com/chapter/10.1007/978-3-319-69453-5_20">
          <front>
            <title>Improved Algebraic MACs and Practical Keyed-Verification Anonymous Credentials</title>
            <author>
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
        <reference anchor="NISTCurves">
          <front>
            <title>Digital Signature Standard (DSS)</title>
            <author>
              <organization/>
            </author>
            <date month="February" year="2023"/>
          </front>
          <seriesInfo name="DOI" value="10.6028/nist.fips.186-5"/>
          <refcontent>National Institute of Standards and Technology (U.S.)</refcontent>
        </reference>
        <reference anchor="SEC1" target="https://www.secg.org/sec1-v2.pdf">
          <front>
            <title>SEC 1: Elliptic Curve Cryptography</title>
            <author initials="" surname="Standards for Efficient Cryptography Group (SECG)">
              <organization/>
            </author>
            <date/>
          </front>
        </reference>
        <reference anchor="BLIND-RSA">
          <front>
            <title>RSA Blind Signatures</title>
            <author fullname="F. Denis" initials="F." surname="Denis"/>
            <author fullname="F. Jacobs" initials="F." surname="Jacobs"/>
            <author fullname="C. A. Wood" initials="C. A." surname="Wood"/>
            <date month="October" year="2023"/>
            <abstract>
              <t>This document specifies an RSA-based blind signature protocol. RSA blind signatures were first introduced by Chaum for untraceable payments. A signature that is output from this protocol can be verified as an RSA-PSS signature.</t>
              <t>This document is a product of the Crypto Forum Research Group (CFRG) in the IRTF.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9474"/>
          <seriesInfo name="DOI" value="10.17487/RFC9474"/>
        </reference>
        <reference anchor="OPRFS">
          <front>
            <title>Oblivious Pseudorandom Functions (OPRFs) Using Prime-Order Groups</title>
            <author fullname="A. Davidson" initials="A." surname="Davidson"/>
            <author fullname="A. Faz-Hernandez" initials="A." surname="Faz-Hernandez"/>
            <author fullname="N. Sullivan" initials="N." surname="Sullivan"/>
            <author fullname="C. A. Wood" initials="C. A." surname="Wood"/>
            <date month="December" year="2023"/>
            <abstract>
              <t>An Oblivious Pseudorandom Function (OPRF) is a two-party protocol between a client and a server for computing the output of a Pseudorandom Function (PRF). The server provides the PRF private key, and the client provides the PRF input. At the end of the protocol, the client learns the PRF output without learning anything about the PRF private key, and the server learns neither the PRF input nor output. An OPRF can also satisfy a notion of 'verifiability', called a VOPRF. A VOPRF ensures clients can verify that the server used a specific private key during the execution of the protocol. A VOPRF can also be partially oblivious, called a POPRF. A POPRF allows clients and servers to provide public input to the PRF computation. This document specifies an OPRF, VOPRF, and POPRF instantiated within standard prime-order groups, including elliptic curves. This document is a product of the Crypto Forum Research Group (CFRG) in the IRTF.</t>
            </abstract>
          </front>
          <seriesInfo name="RFC" value="9497"/>
          <seriesInfo name="DOI" value="10.17487/RFC9497"/>
        </reference>
      </references>
    </references>
    <?line 1913?>



  </back>
  <!-- ##markdown-source:
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
gZ0JhqoIYb7b9vK0F1EF0T+dBVmaSBLiT7Ai+9qKpP53syOlaX83S1Ia+Hez
JaWZfzdrktre056UmP80i/LT7UnLxi+ZtslTJrnQ5IXP3dTGjlLL744fy/qz
MvT9x+oHfTURWH6+Z1U73cV5+yIW7W9tlZNF/UXE7F6LusVss8fRuurO1rbr
GuvZUEVpUpec0Jcmbk3o9zfSetZt/NY2QaUNce6+yF2fInymKZipykm2cazs
Qv7o0EqcvH9QKfBqTfm2ZFqaad/9hXPVVKKjitKkISqJUtBHwLWEkcUz9SI1
KoPXJYfW5/+yMjcrnFUOwyfkExXyDX+0uad4k7I4so4UICobRPOn+WK3eqpK
33m8p3SIC3f0sSWyZgf4q9Z/2fNpbGEcOVP1mJU/1bpeZYsFp7kVWEqeUjFg
uif9ToeUmLJZWV1WmAI+RmYjfbwnaxybj7hrHwrTCuS3h+dsFlZe69xQ4wNj
BqUs65TDyCNikspW6A9Al/lu1URnPSu5B0pzqlYL7GUSPKunvCV4tV4fL1Pg
cWvfdpdJPTKHXLfMmtdSwe0FoW1Z87bhGeTvQPI5V6e2NmubdcXnQnTKT+oO
6UvjPJbl1Mqyk8ngOoD0si0fq3a4ln6XzF40m991hQ1SIpjUXM4Tq6ycKxnF
nizuHXK3FRl5SlsKZdkkH4tm6Yg9WZ9XfiFXOzfJ4hP7DIIqD2RLOqwsVIbW
8avHfyzqFX85FNQR0LWTIlp2ZYFKNYK1g8Kqny3tKZ8k398AwGc3cHBAVs/a
XlN3P123EQCVqMiPXFbukr4sw5iyRrNZalr5or0TNoq87cY9u/GHD4cmvEBr
kLEbe7d4bZ19qzDpxMaBBFXv7VczM39BK/PO5mXroQ0y6e92ZNPDbvnpQWUn
t+G5/SlhfTBG7REdGkiyprunGtqwdaul/0vC94LE4Skd4flewfhBV6+yDmJx
qep3L8JLAfsC5G19hZFVpf/nLZ9M5C9Gz0elIfkJ4739qZVHlF1ZE5qPbXau
WplV7nWcx2V8poICU/j2GRLIfK7A4SIyHgX9FW4yKG6WF3QonQpo6u9OMnVO
Uv300Grdohb+H7V/1EEsstZ7j678k5vkrIpy5yrfLRJV711pWBHsXFlI359V
lYy0gax4DB8iyCTrKJs7yZThSDzAwRvWmH/fhawwOpdZyD0PwCcHh7Vy/n1V
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
IHn7960d/baOvrwb/NaOQVvHwFwodDu0aHCgBIGE8WM9fNXD1z2Cj/UIVI9A
9Xj+kQ7PZXtljCrX+p5OVkuAlPeNfNxrr+7jVqRAxddVHnarw9Y2h6/naDjr
NNI+F69tpECP1OZ/P3Dv7BU+uNUvbMyrNodmjtqW8HmOZOu2lDPW9kHBYtb8
UTf0wb0c0ZbdK0HZtm7g3X3XjwwvccvkYpb3UXf3wb0c3haSaswfWGtrOMh1
v/gjQ27bCbXdm24Z602d7J5ZwH2a9009i2y5XvBXoEeNIXgEJhN1ZZtcuLpI
Vh14WxKNrHEqUdK2Clu3WIj2lKRRZKV1Iz+SeNNK7/65mUo44Z7JmXteBNIS
G/it3effbyS6o4/7m9xI9PnpMtt//gwP+jN86M/wor+AH/3pnvRn+NKf7E3/
0wW0fq2s5G/wzcdnS/tPykm2BQL2pAivvQPb69/XSqYbr29PN17L1GXdn987
s/HoLad9T+OG276n3VYCur0d0O3/obyoccj39XtzYF/U1eKb7+toe+dmgFY3
fd8Id3DU93b9uKu+t+udnPX9MEvX2Ky4zW/fD3W9c4sLvx/ueuemN7+v7/Na
18907Fsy2L+Aa982y6c6921j/TrufcvMv7SD37o9v5WL37qLX9LJ/8gEv4Kb
30pcn+vof2TQe7r6LaP9Uzr7Lev4wu5+s6BGycxaRU3lCG9dS9Nypro+kq1x
PPfHvnagM+oPa26ZdSSn+rbROnGrPLhVfxyxDN8Jc7olH9Yq/Qc6JYPmeeu1
3ZsE2/kjX02YKxj23bgAoa5vBWi7CgBy+s6np+pZaAnqGgJ1WcCwb85VNRcI
tF/51Fbm8dvdM1DGbz7tCOl7HSD93fHjZ8++U9cYWbUBn3GK9Bc8Q9pyrF5b
I975UO//HTcs3+Puux+q+8V0eyEWa2G+/ecAQFsRjl7o4sZ8NJVU9yyrXk5D
I/38xUYqz1+//ez15pngzDfWuqvrNTulP3r+5epIqoD9ut8D/fyJpSS9zSeW
kvD+/PZhlDvWZnye1G5VP3cQ5fcq0LBBvOtnRZU7cvgOplt6/HxAFgNZMi/E
bbUUvQ0a9jbUkpdzS1N+f6CW/SsXL9ytkOBsfxNr9w+qxCDDMfLv28sjTHf9
J3X94bY+P6DxD3esNajcmKQuX7qtE917yOSrkPr6I0h9bSP1tTmI/vYlv+ZJ
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
Nzql2evRSYPxO8f5/3sxmbsWNQEA

-->

</rfc>
