<?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.29 (Ruby 3.4.4) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-yun-cfrg-arc-01" category="info" submissionType="IRTF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.30.0 -->
  <front>
    <title abbrev="ARC">Anonymous Rate-Limited Credentials</title>
    <seriesInfo name="Internet-Draft" value="draft-yun-cfrg-arc-01"/>
    <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="2025" month="August" day="06"/>
    <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://chris-wood.github.io/draft-arc/draft-yun-cfrg-arc.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-yun-cfrg-arc/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Crypto Forum  mailing list (<eref target="mailto:cfrg@ietf.org"/>),
        which is archived at <eref target="https://mailarchive.ietf.org/arch/browse/cfrg"/>.
        Subscribe at <eref target="https://www.ietf.org/mailman/listinfo/cfrg/"/>.
      </t>
      <t>Source for this draft and an issue tracker can be found at
        <eref target="https://github.com/chris-wood/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) = CredentialRequest(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 CredentialRequest(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 = CredentialResponse(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 CredentialResponse(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 = 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.

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)
  # Implementation-specific step: perform double-spending check on tag.
  # Implementation-specific step: store tag for future double-spending check.
  return validity
]]></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: 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: 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: 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>
    <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
[0, <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 [0, 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, return the
result. If it fails, 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
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
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
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
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="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 1684?>



  </back>
  <!-- ##markdown-source:
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
ldWQo0Ub3iKppcAsXVxDa1Ep9IRrt8hPoHBMJo4xqRwk0RuPoQBE0UBtlijS
ysdyG4sAiPqbdbrqWloAwr1j4OqFQBcbBDTQv7IChkphKINgySykFDu1t4Mx
i9K45ioA0QIvFaE0X9JyaMfXtJEya02W7ElpyeyP96QVsXQS9l3N0t3FwJF1
65WJJIny57IZTU4t1UNuj2c9Uipy94qM/f/8z/8AGrh0x/Yz8Kklg/zjcr+n
GoxqLfv2lXOsAij5063/9Oo/HVZXIHT5uN+ERw77s0MFozK5yL/dxm+v+m1V
+7eUomDH7YllRSLG2MCvnAChIXpeOewc1mNGeu5uee5teV6upPv9zzQPJvvW
dFTJZ/zO7Fp7+1R2JEAATdcrggUAdbySbmaLRFx8cuXi/72eMe9Rr4n0w5/R
8Gc0/Nk7YhZQOTy5RyfruNhxUkmqMo6IDO45ltwjd1fsjwBrA/9mBly8eSZ+
+bN9/77d4Yj/7BxVLd2dLV2jpbezJVbxqbnGP1cLUxGYFmmxovqCqNq+lEsg
zYm3iNPqA4EKw285GCeZPtWK/OO90puSs6w32TrNy62NUuOXPoN2Pds6lSxi
qtLaFBWoBFN9D9fawyHs2O7MK00apaxiQ86YqO1J1ejPpAhlcYCau9yxaWjH
xrrKjRwdBCjrV9VPpjYVo5lqreIwmRBOs6Rn1PBanJ4KkiLzM9JXXfXDauuU
YyVxVVClQzX1KlW7aBys8jsVfeRl7GGVsQcHsDL0MDbJK9Ur6URuYNced93V
1dVw7WZlUOdLh7aswZTBiGxUurZd6fYmXdXGUwMPZxzJG75+n9bnqmBeR5R6
c5wMHF4P9OIVgVR43/b61XRAaSwb9aSrXJYE1Noq8eLFVDiS6zd37pXRla25
einiwRpY6hp7F8ZoIrWgah71QBK0MCeuoXmgdqtrWPS2YpGnMhGpuCimMnRo
qhYig2tZLpXnjaJXDY6J4pJO9jXtmygeaoaKqtJ1VYa6ai+vXgXcJbSdix3K
xdJMW7lG1vfK0ViPCrUB3Kj/Mutl8k2gfCq5t3/PjKdVwY6hXBX7Wmo7zG9y
fE+vRNaIUsUvV/rTpn2XHCZ524QdSmqdSbnq6ba0ndmqJTqsF20cWdJ94gqP
+qtj+5Ff+D0NaKX+W0BZyu0yB5F+0dJ9vApL16cHfsp4N4NNADnqDPJAtvXq
bfEOweuWxmqW5yRhx/a//43/6JUyh/9x/Ftl61TCiQFizcPTUUKzhjwNtnb4
NMh1QKu3CsgaaEbnQLtOMUIp4I9w2B4w83b3aExiOJCE8CfH0onEn1XSzsBj
fYu67t+ZfZ7u04f8N3ZVb2QswuRyi5u69Iycp3pe796zD+oPDthv3DJetsXt
ldR+QHB8a2Y0v6ORjCdPGSbV1mu19ZptTe5Dlx/9d6KFD355uISTuoQ3m+G/
Gf7LEPXkZEfVSFR4YL7q1aaghjUulc3NkQ2veps2kP6k1JTqWZ+lRVkFTmJp
Val3/WvC0y39UuSq2JOyE+DfUs/tcMEHW1xwRgV7zNUjr/UovKQa1NWFePMs
Nx5rC+R0P3a7H3vdj4fy8ac2v+/jn0sMNNzziuQe3HLw1/hb3lpp2xJl2BvG
xDOMSQc1DLdc+amy7q9yWGomx9plcionpUkzo9DZKtvVzY18eJg3gryenTcj
+pJDDVvU7NYM3+n7Hn531CuXW63RdgaN+P6G9u6gkQC4ob032JIhMPuVulxu
QROmr5xBtbitOYReR6ShVmRkFrpaqXUY+YauVt7gj2eoTR/jlTG7/saAVUtV
0VHtk0g+7NnnwbdPeAcTgL7igkzT4JXAy1fU7mfnZHNlzrS5ShYJVVusU/qm
hKb4men5s7tHS5dbenu0ZPI8vblhZZMkPeVKb4tqkOlVr0JKB7/kqrypDkL+
D+CJPL4KxZp9cZqfvzK/5r3intxFjmSpW6mhap+S8t5x25vZorfyHYqLZCiJ
1fxbPIHKKX8gvwOXH3/LzW4Dcos247vdmVd4HNS8EzwsCadeHjagHPzs2N+V
35e3VjXg5J2Oi6XU7Wzumc21G8OiogDo6GOmEGuOFAtOvV8Ft8tJxB0N6LiD
p9V7Y2T2hgxx6HDSjLdtG2UZi2+RG4q91xAZXn9PLqcnge4xaKZftmeXXh10
I8FpOleKoXd6V7Z29mTjz/X21JTa3ev03F7VXbRyvfXHvPbGI7f9yGs9etp6
8hWdwObjUffjcffjSZcnKV/dOdNreF4T6UvODF/yB5W8MZ3Khi85vNmXrAzo
NrtQZZ0sndpT37Ap9bszo9FKgFgq6aQTS7VPmOWmeed4HV6quTv4oMRHhY5m
qLRd4jUWaj7qHy5z0PY829tr+aVPH9KVSU+VCUw3RT+N+wFVCv3hfMfKOZIQ
38F/HGj/kfrv50FKp34/H1K69vt5kdLB38+PpLa39CQl5u/mS97dkzS8+0po
2zJVbiK0ZeFzidqiKLX88eShrDOrUtzf1D/ca6jA6jM9o6ppn7Dti/iyv7c/
Tr70F1GzWz3qDrfNHEfbqr29bdsuveeSKyqXupKEgXRxG0p/kEnvWbdxO9t4
tTYkuduydQPK6pVNIUx1STKdY+UX8seFxgbJx3u1Qq7Ord2OHZX29u72Arn6
lqGlis+kIyqZUtDHvo2NIUNmmsVoVO6uSwuNz/xlBW6SW6sUjo/PJyekGX+c
uaVIk3ZrZL0oQFQ+iJbP8svc+ukpA+vhlhIhLtDRx5PI2hzgr17nZc6nsYVx
5Ez141T+3Oj6IVkseDtbgaX0KRX9xVu22ekwkrI8VlaR5WWhHiOztU28ZXc4
LD/WbnwQTCuQ3xhesFtYe613glofEjMoVfmmHEYeBRPVSKE/9Fymm1Ubnc3d
xy1QlqdndcBebXYnza1tCV6j183lCDxu4xvuavOO3CHbrnbHG1u+3YWfXbvj
XcMzyD+C5VOuQu1s1jXris9/OKw+nTuiL4rTUJZNK89Obvo2AaSXXfuuisKN
bXYp7Hm7+b4rbLESwaTmsh4Z5eNcsSi27NbusUdb05FnRFIYyzb7GDxLR+nJ
OrzqS7jG+UiGnJhnDdRlIFnSoWS+crROXjz8Jm9W9qUwUMdA10aqaNmVFSrV
AjYOBKt/nrSlTJJi/xIAPqOBkwOyStaMmnrb+bqLAagURX7MsrKX9AUZxpS1
mO2S0tqX64d+q5jbbNw3G3/6dFSmF2gNMndjUovXdrhtFeUWYuvggXr09tXc
zN/Qy9zbvew8nEFu8duHsulRr/rEoEbJwr8wPxlsDsaoPabDAUnX9LZUPZdi
3enp/5bwPSN1eEZHdX5UMH7SVapsg1hdqjrdS/+9gH8B9ja+tkjq2v/zlk8u
8hfj5+PKkbzDeG9+6ZQR5Vc2lOZDU5zrXmZdei3rYZWfqaGgLHD7DA1UfpbA
6SJyHgX95WcJDDfrCzp8TiU09fcliToPqXlKaL0+USv/G/0fdeCKrOneYiv/
bEcpm6LU+pBuFpGq6641rCl2riCk78zqRkb6QEY+hg8LZJa1lM8dJcpxJBng
5A1bzP/a+GwwDt8nPvc8gJwcHDXK9rdVH1kN2tEhdvR1n5+rT+g6XcfS107V
x9aAcLOOeAU1EeLmSsuvxAdm2J5cVoMhHmg2POQ+hgrn38cKnBb7s140qEs/
v6CKaQ73xZVMc4K7a1mN3+OSFG1k9SWAjfGlI9nlOzZiqDqo7SRbJvqGpSwd
+FfadStDXsNGPkyXvGLD2homTTmV6oMPM+W2dPfqWfv2jMppjmR3ULphnYn2
+ovdkmCCjpAMdYzbHQ3VsXLrXFpz4H+4/VZmycfqg5eOVFWH109h31LQFgEf
HRnK44k7MVi6Uds1sbSmdf2gMkd0BptUMl1SemT/9YHdfi1lzMgUtVdIW4v+
liq07se/dj1Wu7k+bWsyGEYA8cpMSnW34LdlM8nvaKx6fQdQGrvEWijsB+3R
uDruFXr92tpEvacDerFW/n5eBcVUBPxOiDULAUdLXExwD8SnQ1GlwmNd5y9g
VaJrqfMQFK5YPKR2ebDf6ZKO2pPtplmv40VJa6urm3478KPokCFhopTLf9n6
KrvTheLT9mgGUhIP7MM6Wr+Tazz6v4d998hE7kv0eI32hHGjy88uZRzbtHvJ
g3cTjo5ls+y2pukIm2TWtMwqSo7olbzRo7GM79Zf9mpu2msId8/+tbTSDNZR
c25Cwk0ztGA9sio/Nt/qCkjH9M2bn54/fmafnp29enxMn6+Tc6XVNB8WFaeL
7uJxViv/55dfmrvpddWyx456zflVu+rW/rvq9fzrLbbTTaw2yiPdrqdAye9Y
Mvm8RbuOLe7GjnaDlUbtCslaUGLeK1H/CEy6tF25qUAd/n7dabylTfYvKK9W
qNH6+pMiSx7VqYIT43g9IFZwtqgr70cftqZ0yGZXIkz7a4Qfzg6Sy/5AbVGY
a71FIWVnwFg+7JCsm1Il/yzG/ErFmLf+9OKLJ3b+GQb844cBXyow1Prm2P4+
TRfChx54mUE2kg4zpTcvevYPtJ0qP1CkWxD+4aKS0xUDyg7elqBkG0O315zI
wWSg8fsrZRXcSPj/YjvynBH68dcOnjACmRZSPsvZ1R6pMUDfll40PNIasxbK
R9xp27ZUYd4Rl3UkKjeV4pLT2vlD1ce4FN4ca3tuRynmE/RW2gtp2qW2HOwx
Dm9Ss7bgmq0NOzedgw4qr1ejR/pJuybIj81ddT4dUEPeckMIiMMWOejcZIsS
mOvqoBkZmeFfPblfK+g+CgW1raHm7R9O7/Ea83IOWuiGv32tr9eqr5c+YaXz
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
FWaVXcOP5hGy5afPtR3f6lyb8vD0s2qbW+5pvRfqJGp3cIszd73BLQ7dLd2+
bciQHx2mKkH7pU7oNWzH9qOddh7sdNtjne5wqNO+BzDd4vgl04ytaxWL8rs6
zaMVpLUcQdNrkdwnTz9QkyX6K7qy+Lw+VmlfW+U8S7fe0d27o1fv6O3bMWvM
ONy7o/f72/O+3pw9KzKujVZFsBxWVd8j30U8jvnjD7b3D1QhxWFtMgjyQWvg
A9amSxeGRloPOp2j5iceLN0DmkqeFb6rnUft5OnXu8bLaLzMlWeF72pH49Fp
2rI68klHUx0n0yWMTw7Max6PZKenN3R6elC7fd5Sx5Tv6sUNDhTyJVJu6uGp
HkqNUY7vVspZE3ZQ7RZpMHv2m0OmXk/jCHH+YVY+IQQc/aImvZWS75rUMyb1
WpN6HZMq06qG0rtKNxqQ+rcknd9j3HC0a8ddCn+UE/LIG/qSav0zFPtnqPbP
UO53V++3KagnjJWn5pTB0V5B4MU/mtHYSySI/8t03IMyZ3drK6HHaNsJ00Zs
a+UdmBZiS6tMjpXtHivzDhrWodFwX/uwo9tOC7Gtn7YRtaOcG7Zia1+v0ffu
VqOc4uvaja5p72w5ysFUkkKjZW2cx9wwJEpDVHFZ7cjl8oNT4wTlnZFZ90V4
CAeOaiq4PCqoA5T6cX6NNvsEctWdgDXcbzvMGwSrLgM0ng8Hxk2AxvPRoHZq
+PYzwkf+YMsp33gXHJej1EbgDoc7hz6yxoPaAeRNyG177Fctivpb+7Bwy34k
ZuOgPhqQcdiFkCNrMqgda95EjG1P/HoL4O+wC4c07SSo2hZeE0SvnOPImg66
DpCfDdonyNOJ8RJsSBB9Ekc/Pf3TO9riTNVkoBmOf8Zh7F/oIPZ/fs/69b9n
/aO4v/9LLwX5DbM49U91b+3qXzl3zOFcuXfM4Vx5d8zhVGJYH2C07wBBvd94
335FY6mTvTv+MbNOX8EI3DphJWGSLv+VsyNzdOUc9Fp2ZXDlyNuad3V0Ozu6
8jrnXR29zo5e/b7nnSDrRt2gl/cv0+bZjnGCA3JM0ajYtc6C1tl1P4xaa7Fr
rYW3tfM/bLJuVyC2O2nXul7n1a5er9DjFbUqJWBX67LRgSEy8gqfXd1+Ntjb
uFlIXgG+s6Pb1dGVF4Tv7Oh1dfTK24Z2Q4sGB0oRSBhv6uGqHq7u4d3Uw1M9
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
jcwymxWIsLiWImW6/HJAiixZrlNIxFLJe0/nwaXmkNEGHT0vsNpwkeZCInmd
fuCAwvJ66gZoiKlYFzomTil5I9WTpnNBB2eSwVmIgi7ThQZaWWwcwg2HPt0z
r8urqDO+TMeIhQKrunz5v9eQBe8vCEL+GvzlPv3nv6n1AsaNGqzUu8Pgvnck
33MkuLLOTd/1XN4UTnTQXmuXy1oGYzE40FqmWFhgB0mhbq/UovhMHv1viOIr
1iGPr4rM142+T+gGnT1Ynxy1UCSLw8PDof2t/HORXniHpbjhH/s+3Z9y354d
nVuGnPAV1GvaKwNZfBOJf7aN29X1utgxS2uKRl7Z3JKIMyGg7/YKesdG5GWw
Jv6gpLxKYJz//ZzvT0enTUYmi5JRsF8Sf0AURcx+drGRZbGS2ZVlXoHWJGyY
5EL4QUJZD1p+urpeqj/V5VO888jXbCuzb96PTrlTRod18ANJ1aIC5pFgQ83h
Pi3lb+JaRH1zF98+4enoau8ql58fyLjpb69PHlLEVA+yxQKryKQTsgL4APCd
gp5ggh9FqQyej8CkRUhN0x1NWysRkgsPeVXYlucH6nEgnJcph/q1r6dtfbTt
KxMAy3ooc1rtTWh5qbCZKandhK73vCFPZNgieWXGJskvy8ti/BXcU1iirrHL
XWa+99tIrFGHeqsoiTmvVKhmUKn/KmSySW4XkxKR678m3i9pX0O1MtZlQ9Zo
l4l4Lz0HAuWDf71lQ76FC5iKlW3qNpneaHWs36eMpT1HC8QvpOkpjy25nOU/
hshdNk9358t46fJkml/Xm8uuUk9zr1qFaH3rXIp1CQvFbDK7UbmV+nWSSyUM
rhJ8SQLfhUOeqn2ZyMMmpaqJBKX4S3dImcVdlB3YP6Z8K47MB2kTRgmuLnG4
1jdex+lmFZmypS5wf/H49enZ6cvTZ0/eljJX5/ZTzQQNdn9pcG5JAQ5Nr5xz
8y43MNJ59cXWk8GFsZvb/Gqrvm/LdxXpFC0nIw2tYuoJFcPkZrUGoztIqk+N
GV4mJQVWBKXqtxT+SoUJQKI0g4LkkBoLG5aDhg6y9J1Q93xX7Jnr0gzW01BL
XUjB8mnvo2cPBoNzeWe3L+/trnUuSV2rwT7X55VSZ8t6CndC5cttPyLvn/RX
kMG5KbFkQn4oBhcDqsL4L1Cx2CyrTkfSzSYlTzd3YCZ5NGp1NpW0ZfT4G/P5
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
prPe/X7fDjCVZf0/aYjvxAIXAQA=

-->

</rfc>
