<?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-irtf-cfrg-fiat-shamir-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.30.0 -->
  <front>
    <title>Fiat-Shamir Transformation</title>
    <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-fiat-shamir-00"/>
    <author fullname="Michele Orrù">
      <organization>CNRS</organization>
      <address>
        <email>m@orru.net</email>
      </address>
    </author>
    <date year="2025" month="August" day="09"/>
    <area>IRTF</area>
    <workgroup>Crypto Forum</workgroup>
    <keyword>zero knowledge</keyword>
    <keyword>hash</keyword>
    <abstract>
      <?line 37?>

<t>This document describes how to construct a non-interactive proof via the Fiat–Shamir transformation, using a generic procedure that compiles an interactive proof into a non-interactive one by relying on a stateful hash object that provides a duplex sponge interface.</t>
      <t>The duplex sponge interface requires two methods: absorb and squeeze, which respectively read and write elements of a specified base type. The absorb operation incrementally updates the sponge's internal hash state, while the squeeze operation produces variable-length, unpredictable outputs. This interface can be instantiated with various hash functions based on permutation or compression functions.</t>
      <t>This specification also defines codecs to securely map elements from the prover into the duplex sponge domain, and from the duplex sponge domain into verifier messages.</t>
    </abstract>
    <note removeInRFC="true">
      <name>About This Document</name>
      <t>
        The latest revision of this draft can be found at <eref target="https://mmaker.github.io/draft-irtf-cfrg-sigma-protocols/draft-irtf-cfrg-fiat-shamir.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-irtf-cfrg-fiat-shamir/"/>.
      </t>
      <t>
        Discussion of this document takes place on the
        Crypto Forum Research Group 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/mmaker/draft-irtf-cfrg-sigma-protocols"/>.</t>
    </note>
  </front>
  <middle>
    <?line 45?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>The Fiat-Shamir transformation is a technique that uses a hash function to convert a public-coin interactive protocol between a prover and a verifier into a corresponding non-interactive protocol.
It depends on:</t>
      <ul spacing="normal">
        <li>
          <t>An <em>initialization vector</em> (IV) uniquely identifying the protocol, the session, and the statement being proven.</t>
        </li>
        <li>
          <t>An <em>interactive protocol</em> supporting a family of statements to be proven.</t>
        </li>
        <li>
          <t>A <em>hash function</em> implementing the duplex sponge interface, capable of absorbing inputs incrementally and squeezing variable-length unpredictable messages.</t>
        </li>
        <li>
          <t>A <em>codec</em>, which securely remaps prover elements into the base alphabet, and outputs of the duplex sponge into verifier messages (preserving the distribution).</t>
        </li>
      </ul>
    </section>
    <section anchor="the-duplex-sponge-interface">
      <name>The Duplex Sponge Interface</name>
      <t>A duplex sponge operates over an abstract <tt>Unit</tt> type and provides the following interface.</t>
      <artwork><![CDATA[
class DuplexSponge:
  def new(iv: bytes) -> DuplexSponge
  def absorb(self, x: list[Unit])
  def squeeze(self, length: int) -> list[Unit]
]]></artwork>
      <t>Where:</t>
      <ul spacing="normal">
        <li>
          <t><tt>init(iv: bytes) -&gt; DuplexSponge</tt> denotes the initialization function. This function takes as input a 32-byte initialization vector <tt>iv</tt> and initializes the state of the duplex sponge.</t>
        </li>
        <li>
          <t><tt>absorb(self, values: list[Unit])</tt> denotes the absorb operation of the sponge. This function takes as input a list of <tt>Unit</tt> elements and mutates the <tt>DuplexSponge</tt> internal state.</t>
        </li>
        <li>
          <t><tt>squeeze(self, length: int)</tt> denotes the squeeze operation of the sponge. This function takes as input an integral <tt>length</tt> and squeezes a list of <tt>Unit</tt> elements of length <tt>length</tt>.</t>
        </li>
      </ul>
    </section>
    <section anchor="the-codec-interface">
      <name>The Codec interface</name>
      <t>A codec provides the following interface.</t>
      <artwork><![CDATA[
class Codec:
    def new(iv: bytes) -> Codec
    def prover_message(self, prover_message)
    def verifier_challenge(self) -> verifier_challenge
]]></artwork>
      <t>Where:</t>
      <ul spacing="normal">
        <li>
          <t><tt>init(iv: bytes) -&gt; DuplexSponge</tt> denotes the initialization function. This function takes as input a 32-byte initialization vector <tt>iv</tt> and initializes the state of the codec.</t>
        </li>
        <li>
          <t><tt>prover_message(self, prover_message) -&gt; self</tt> denotes the absorb operation of the codec. This function takes as input a prover message <tt>prover_message</tt> and mutates the codec's internal state.</t>
        </li>
        <li>
          <t><tt>verifier_challenge(self) -&gt; verifier_challenge</tt> denotes the squeeze operation of the codec. This function takes no inputs and uses the codec's internal state to produce an unpredictable verifier challenge <tt>verifier_challenge</tt>.</t>
        </li>
      </ul>
    </section>
    <section anchor="iv-generation">
      <name>Generation of the Initialization Vector</name>
      <t>The initialization vector is a 32-bytes string that embeds:</t>
      <ul spacing="normal">
        <li>
          <t>A <tt>protocol_id</tt>: the unique identifier for the interactive protocol and the associated relation being proven.</t>
        </li>
        <li>
          <t>A <tt>session_id</tt>: the session identifier, for user-provided contextual information about the context where the proof is made (e.g. a URL, or a timestamp).</t>
        </li>
        <li>
          <t>An <tt>instance_label</tt>: the instance identifier for the statement being proven.</t>
        </li>
      </ul>
      <t>It is implemented as follows.</t>
      <artwork><![CDATA[
hash_state = DuplexSponge.init([0] * 32)
hash_state.absorb(I2OSP(len(protocol_id), 4))
hash_state.absorb(protocol_id)
hash_state.absorb(I2OSP(len(session_id), 4))
hash_state.absorb(session_id)
]]></artwork>
      <t>This will be expanded in future versions of this specification.</t>
    </section>
    <section anchor="fiat-shamir-transformation-for-sigma-protocols">
      <name>Fiat-Shamir transformation for Sigma Protocols</name>
      <t>We describe how to construct non-interactive proofs for sigma protocols.
The Fiat-Shamir transformation is parametrized by:</t>
      <ul spacing="normal">
        <li>
          <t>a <tt>Codec</tt>, which specifies how to absorb prover messages and how to squeeze verifier challenges;</t>
        </li>
        <li>
          <t>a <tt>SigmaProtocol</tt>, which specifies an interactive 3-message protocol.</t>
        </li>
      </ul>
      <t>Upon initialization, the protocol receives as input an <tt>iv</tt> of 32-bytes which uniquely identifies the protocol and the session being proven and (optionally) pre-processes some information about the protocol using the instance.</t>
      <artwork><![CDATA[
class NISigmaProtocol:
    Protocol: SigmaProtocol
    Codec: Codec

    def init(self, iv: bytes, instance):
        self.hash_state = self.Codec(iv)
        self.ip = self.Protocol(instance)

    def prove(self, witness, rng):
        (prover_state, commitment) = self.ip.prover_commit(witness, rng)
        challenge = self.hash_state.prover_message(commitment).verifier_challenge()
        response = self.ip.prover_response(prover_state, challenge)

        assert self.ip.verifier(commitment, challenge, response)
        return self.ip.serialize_commitment(commitment) + self.ip.serialize_response(response)

    def verify(self, proof):
        commitment_bytes = proof[:self.ip.instance.commit_bytes_len]
        response_bytes = proof[self.ip.instance.commit_bytes_len:]
        commitment = self.ip.deserialize_commitment(commitment_bytes)
        response = self.ip.deserialize_response(response_bytes)
        challenge = self.hash_state.prover_message(commitment).verifier_challenge()
        return self.ip.verifier(commitment, challenge, response)
]]></artwork>
      <section anchor="group-prove">
        <name>Codec for Linear maps</name>
        <t>We describe a codec for Schnorr proofs over groups of prime order <tt>p</tt> that is intended for duplex sponges where <tt>Unit = u8</tt>.</t>
        <artwork><![CDATA[
class LinearMapCodec:
    Group: groups.Group = None
    DuplexSponge: DuplexSpongeInterface = None

    def init(self, iv: bytes):
        self.hash_state = self.DuplexSponge(iv)

    def prover_message(self, elements: list):
        self.hash_state.absorb(self.Group.serialize(elements))
        # calls can be chained
        return self

    def verifier_challenge(self):
        uniform_bytes = self.hash_state.squeeze(
            self.Group.ScalarField.scalar_byte_length() + 16
        )
        scalar = OS2IP(uniform_bytes) % self.Group.ScalarField.order
        return scalar
]]></artwork>
      </section>
    </section>
    <section anchor="ciphersuites">
      <name>Ciphersuites</name>
      <section anchor="shake128">
        <name>SHAKE128</name>
        <t>SHAKE128 is a variable-length hash function based on the Keccak sponge construction <xref target="SHA3"/>. It belongs to the SHA-3 family but offers a flexible output length, and provides 128 bits of security against collision attacks, regardless of the output length requested.</t>
        <section anchor="initialization">
          <name>Initialization</name>
          <artwork><![CDATA[
new(self, iv)

Inputs:

- iv, a byte array

Outputs:

-  a hash state interface

1. h = shake_128(iv)
2. return h
]]></artwork>
        </section>
        <section anchor="shake128-absorb">
          <name>SHAKE128 Absorb</name>
          <artwork><![CDATA[
absorb(hash_state, x)

Inputs:

- hash_state, a hash state
- x, a byte array

1. h.update(x)
]]></artwork>
        </section>
        <section anchor="shake128-squeeze">
          <name>SHAKE128 Squeeze</name>
          <artwork><![CDATA[
squeeze(hash_state, length)

Inputs:

- hash_state, the hash state
- length, the number of elements to be squeezed

1. h.copy().digest(length)
]]></artwork>
        </section>
      </section>
      <section anchor="duplex-sponge">
        <name>Duplex Sponge</name>
        <t>A duplex sponge in overwrite mode is based on a permutation function that operates on a state vector. It implements the <tt>DuplexSpongeInterface</tt> and maintains internal state to support incremental absorption and variable-length output generation.</t>
        <section anchor="initialization-1">
          <name>Initialization</name>
          <t>This is the constructor for a duplex sponge object. It is initialized with a 32-byte initialization vector.</t>
          <artwork><![CDATA[
new(iv)

Inputs:
- iv, a 32-byte initialization vector

Procedure:
1. self.absorb_index = 0
2. self.squeeze_index = self.permutation_state.R
3. self.rate = self.permutation_state.R
4. self.capacity = self.permutation_state.N - self.permutation_state.R
]]></artwork>
        </section>
        <section anchor="absorb">
          <name>Absorb</name>
          <t>The absorb function incorporates data into the duplex sponge state using overwrite mode.</t>
          <artwork><![CDATA[
absorb(self, input)

Inputs:
- self, the current duplex sponge object
- input, the input bytes to be absorbed

Procedure:
1. self.squeeze_index = self.rate
2. while len(input) != 0:
3.     if self.absorb_index == self.rate:
4.         self.permutation_state.permute()
5.         self.absorb_index = 0
6.     chunk_size = min(self.rate - self.absorb_index, len(input))
7.     next_chunk = input[:chunk_size]
8.     self.permutation_state[self.absorb_index:self.absorb_index + chunk_size] = next_chunk
9.     self.absorb_index += chunk_size
10.    input = input[chunk_size:]
]]></artwork>
        </section>
        <section anchor="squeeze">
          <name>Squeeze</name>
          <t>The squeeze operation extracts output elements from the sponge state, which are uniformly distributed and can be used as a digest, key stream, or other cryptographic material.</t>
          <artwork><![CDATA[
squeeze(self, length)

Inputs:
- self, the current duplex sponge object
- length, the number of bytes to be squeezed out of the sponge

Outputs:
- digest, a byte array of `length` elements uniformly distributed

Procedure:
1. output = b''
2. while length != 0:
3.     if self.squeeze_index == self.rate:
4.         self.permutation_state.permute()
5.         self.squeeze_index = 0
6.         self.absorb_index = 0
7.     chunk_size = min(self.rate - self.squeeze_index, length)
8.     output += bytes(self.permutation_state[self.squeeze_index:self.squeeze_index+chunk_size])
9.     self.squeeze_index += chunk_size
10.    length -= chunk_size
11. return output
]]></artwork>
        </section>
        <section anchor="keccak-f1600-implementation">
          <name>Keccak-f[1600] Implementation</name>
          <t><tt>Keccak-f</tt> is the permutation function underlying <xref target="SHA3"/>.</t>
          <t><tt>KeccakDuplexSponge</tt> instantiates <tt>DuplexSponge</tt> with <tt>Keccak-f[1600]</tt>, using rate <tt>R = 136</tt> bytes and capacity <tt>C = 64</tt> bytes.</t>
        </section>
      </section>
    </section>
    <section anchor="codecs-registry">
      <name>Codecs registry</name>
      <section anchor="elliptic-curves">
        <name>Elliptic curves</name>
        <section anchor="notation">
          <name>Notation and Terminology</name>
          <t>For an elliptic curve, we consider two fields, the coordinate fields, which indicates the base field, the field over which the elliptic curve equation is defined, and the scalar field, over which the scalar operations are performed.</t>
          <t>The following functions and notation are used throughout the document.</t>
          <ul spacing="normal">
            <li>
              <t><tt>concat(x0, ..., xN)</tt>: Concatenation of byte strings.</t>
            </li>
            <li>
              <t><tt>bytes_to_int</tt> and <tt>scalar_to_bytes</tt>: Convert a byte string to and from a non-negative integer.
<tt>bytes_to_int</tt> and <tt>scalar_to_bytes</tt> are implemented as <tt>OS2IP</tt> and <tt>I2OSP</tt> as described in
<xref target="RFC8017"/>, respectively. Note that these functions operate on byte strings
in big-endian byte order.</t>
            </li>
            <li>
              <t>The function <tt>ecpoint_to_bytes</tt> converts an elliptic curve point in affine-form into an array string of length <tt>ceil(ceil(log2(coordinate_field_order))/ 8) + 1</tt> using <tt>int_to_bytes</tt> prepended by one byte. This is defined as  </t>
              <artwork><![CDATA[
ecpoint_to_bytes(element)
Inputs:
- `element`, an elliptic curve element in affine form, with attributes `x` and `y` corresponding to its affine coordinates, represented as integers modulo the coordinate field order.

Outputs:

A byte array

Constants:

field_bytes_length, the number of bytes to represent the scalar element, equal to `ceil(log2(field.order()))`.

1. byte = 2 if sgn0(element.y) == 0 else 3
2. return I2OSP(byte, 1) + I2OSP(x, field_bytes_length)
]]></artwork>
            </li>
          </ul>
        </section>
        <section anchor="absorb-scalars">
          <name>Absorb scalars</name>
          <artwork><![CDATA[
absorb_scalars(hash_state, scalars)

Inputs:

- hash_state, the hash state
- scalars, a list of elements of the elliptic curve's scalar field

Constants:

- scalar_byte_length = ceil(384/8)

1. for scalar in scalars:
2.     hash_state.absorb(scalar_to_bytes(scalar))
]]></artwork>
          <t>Where the function <tt>scalar_to_bytes</tt> is defined in <xref target="notation"/></t>
        </section>
        <section anchor="absorb-elements">
          <name>Absorb elements</name>
          <artwork><![CDATA[
absorb_elements(hash_state, elements)

Inputs:

- hash_state, the hash state
- elements, a list of group elements

1. for element in elements:
2.     hash_state.absorb(ecpoint_to_bytes(element))
]]></artwork>
        </section>
        <section anchor="squeeze-scalars">
          <name>Squeeze scalars</name>
          <artwork><![CDATA[
squeeze_scalars(hash_state, length)

Inputs:

- hash_state, the hash state
- length, an unsigned integer of 64 bits determining the output length.

1. for i in range(length):
2.     scalar_bytes = hash_state.squeeze(field_bytes_length + 16)
3.     scalars.append(bytes_to_scalar_mod_order(scalar_bytes))
]]></artwork>
        </section>
      </section>
    </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>
      </references>
      <references anchor="sec-informative-references">
        <name>Informative References</name>
        <reference anchor="SHA3" target="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf">
          <front>
            <title>SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions</title>
            <author>
              <organization/>
            </author>
            <date>n.d.</date>
          </front>
        </reference>
      </references>
    </references>
    <?line 354?>

<section numbered="false" anchor="test-vectors">
      <name>Test Vectors</name>
      <t>Test vectors will be made available in future versions of this specification.
They are currently developed in the <eref target="https://github.com/mmaker/draft-irtf-cfrg-sigma-protocols/tree/main/poc/vectors">proof-of-concept implementation</eref>.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAAAAAAAAA9Vb3XLcthW+51Og0nSy2+xSsuQ67nbcqetGiSap47Gc9sL1
LLkkdhcVl2QIUtLG45m+Q5+m132TPknPDwASJFdS+nNRTyYjgcDBwTnf+QU0
n8+DWtWZXIijCxXX86ttvFOVeFfFuV4X1S6uVZEfBUlcy01R7RdC5esiCNIi
yeMdrEqreF3PVVWv58m62szXSEQTkfnpaaCb1U5pDTTqfQnTL798dxHkzW4l
q0WQAtFFkBS5lrlu9ELUVSODm4U4D+JKxsDS5dt3F0fBbVFdb6qiKWHkVbUv
60JcFFWzOwqu5R4+potAzMWPsirEdV7cZjLdSBzZxnob3Mi8gV2EGKcgBDN2
9FZqGVfJVnyF8/DDLlYZfMBj/VbJeh0W1QbHcRaMb+u61IuTE5yGQ+pGhnba
CQ6crKriVssTJIDrNqreNitYudvF17I66YtOq80unpdVURdJkWlckoGEdN3d
jJaGTCpUxUNEBt87+gm39S47CoK4qbcFqGMOGwqxbrKMVXv0B5VsZSbFd1X1
j78f0Vc4W5yrHwkVC/Hq9dsrGpZGVrvfFlXVhLmsgW7O8LkB6QeIGvebEFdf
vzxf0EoLPhiZn4urOs7TGBQq3shq19S0z/x3sZap+Bq0KeCz+PKuljBrlcn5
d01dNrW4aPIEZ2pmso6rjQSpWaHlN1nZrHSYK12Hm+LmBH/AkZOLyzdXJ68v
r96F+FN4dnoWluk6CObzuYhXuq7ipA6Cd1ulBSC+2cm8FqnUSaVWUottcSsA
SQhgQG5Si1jkwK7Ka4kL4awCFFGsxY2KRb2VAi3sn3/9m7Gx2rOxmWi0yjdA
YyNzWakE1yYybSoJa+MattmVKoNt41wMt4CRYmT/IpditReVzPZIvMhhjgax
SlAz2YcoVn+RwDptAaRuVIpbiLQpM3kndFnkG8n7reNEhigNeegr7PNDoyog
UN8WYicBVymYNUiyqFakO/1DI+WPciZutwAumK9LSZxmyGSc0qTbStVSAPJQ
3lrA6YBpmKfWCnCwAjSQ0YYCWTHEixLOjHIEbpKKVsYZEG1K9DKaxM/sfqaZ
4Tw2EiB5EEeZ5HnMZIcmCCZtEiBzE1eKkJfJfFNvQWl5WclUJTWOioLwqJEz
pTtySUBnKxQU7JXXgAI4xy3YMNErGs2MrC2M6YwpaqtszQBsjzAAMkN/2s4O
DUKNiBKeHWe6AKyuVQ5sJ0UqE41g1TJpEA3g3cpWxOuq2NHREQGyYjTVA0Wn
Bdg5IBWV5JaMTWECQAlVVgEStI43EjlFy9qpNM1kEByLy7wmySLHjKxuEPIN
RCjEZS2Tba5AQYzYRhNaPfEZm4Td0SLBzjOVzJNCDcyGXCTopb6VEg3DHB5P
F7fMG8tKwLNJPGSKhjRi50QtDC7RQ5TgoAC4OXi+uXiZi6XKFag9M54TiCd1
US3F5PKPU4AQngdUAqYH4FiTpRplENEZo5L1ztKnAcQtuaSVxCXEfh66HYfc
LYVuyrKoanY0a5AybAv25UgRRlayS0ssPekuhdqVjBvL5wFvMAPYl2wWa2Om
uELlaCI9M219A07pWVnPyFo0EXeE7aX1KA7fQDwutdWpQ7pDNrmROCu3MQCA
hWqsF9kdPdYIosUE7VFWN04WEFogOjQoqmmIGEdU/55JXTGpSyuhIHjZ24Vd
DtA1SHRRSETfA4QicnzErPPVuOu6yLLilqXbemqMhUkWa2325+057gr0DSKX
txMFCddqD3tOxfw33szORFbfRMtsPRN3C5HBMd8jRx+mnVnGcZpprDzMGGsi
3a4Jgj9tZSXJOiI0jXuYiIByXlgX3rMjC0rjcFsPAFkS+AXNYAOon5/NkXx/
Pdsh8HATkVDdZxsx0C5G8YDgizyp3MRZI7UnGp/3QaQydA3Bh46AdHGJAYJD
NPJNMcJsE/nSc7GOzkJsH1aTz/AwDv4kjtnfbirYO+JNom4OoO85EwwZ07cr
nSm9QnNvYY4mRB7gpxkEUbGWcMgWaJI3h73J0li/EaA/OPUWWIexTLbg5+Ao
vIjID7/9f9oFiZ+A9Rjx4Dnww+Nsg2k/dArj5M0WfT6igYkQ1W4e2NrGT1PY
I+3lnlPkhQ2IyCSlM4c5xOBsUlE0Lz8sutjkuBs7DRvSV1hieCxe+gD4IwPg
47G6mW/c5E+co42DhdIzgydIRiEKUkiEJE1CuQ91AOVCpBxORlQaLWhvToBs
+oNHgKTPwHokYbP5D9hxkXAuDRGfeRlkQuDtOG9qtzMDnf1mtCEIv5obL5Ji
BlnLu7oB2bviFdPqFWQJRkU0AfIOWUmbr2ElpiG3TqWYyHATgki+f/vtDHN3
yF0VILKOd+XUJGkRFwSJXGaQhWSGPzs4JpBDOR+mnVhx2NQMDgD2wV5QG8+H
adyScfTCcyUhuZr3px/EL0CB097k0ES5y7Pvrt5MAESTjganM/F0emhFd96D
RFs13UuzM82UPbcqwyReyLsSkCHRWYGR1Vg3A/w11VME8n6JRJZwT72BMr/C
dop4Y9sp4KClawAM6//R6l8TIerLOAyDSh4udsq4iqGGrsDrQtW7J/uJRURR
KXL5rqmLXTfCeFLfJbJ3MTOsmxo6DP1r3oJObQ89slWvA3E+t563LYOC70uq
xbueYuZVNWC0iYTlfspAIQfU5RwJ792vkZTxkwOnYI27ax70cVKUyANWG1MY
l3Nqr2h0uLrYyQNG7uhzc6Zrnl4+8frSk1mbWbgR4U1w3zkRMamGlzqQUXII
dVnAzO0+bbfAfzgv9AycRogsJBHT4WRV2kmWp4mjHQyTHsPJrapzENpMVPmm
x8LERF3TTkmK3U7V6IumdiNVhmYOf5x41DxibQx70T9b2MsyOhuFI9Hbp8sl
vJZDluyX/jEsoY5Q8B8oHfsLlojduMNNZ+3M7dvnBtxU7ogARU6yli2V7vHE
5yNTHd/tFsMMdN/mYsW6p7d2gyVb3Aue9n5hN3OI56k8bQkn+zAq2x6ZB6ks
Phzgp6OkVD4gHCb3oLK7dAaSG6PxvwOip/rH4yc4PjY1EIaVb1Uu40pQq+Pj
MV1xUAojP/mhKjZFEsW0ZJsXVWWjE8UJWklxsqwgS4F8JYXRqIw4gzPNTAqv
SMIrhbVJgaiIAzE1zyPPNzKPf4jLXtH1FV/I8NYh/QarXxe5dFO8voX3m+uh
2CUP+s7HeczuHuQ4H67/bNXKpf/924SdlgEfuTXliSU09aFyLBLAgbZNZEAF
CDQ9hKYR6x8pZ3wmIbpi8HOG22faNgy8Re50fIwrYDKuLpTM0lDTz0RuyfX7
BJ3Xk2cegV5QojWw+XdXZ5dvJh5LU/HzQ1sRUEdlQZMwxXulSsCnbhRQIvO5
+vrlN18+OXseBPYnLl76bUe/q+x68pgEfCOTJL62XTuXAeK8jx/xduvTp1Bc
YpaewQzqquIyvuUyfddVg72PNbCGvVhAnWqvEIS9X/BafcjpSnF/hBqdqt6L
eBOjawUmMsAfpS91HSfXGFblJq7SDNBqyzyPOl3XQEUiU0yFj497RSAjCdsi
1pKMNVxSwbrgX+YwDmySjYm4quI9j/PVXDvLdunZ2jr9G/z8JBRbxN0WauIl
nNKlLGeh1eeWWXQae0mGxMuNUbWInYm7cV67U7oMmc93YydB5kK+R5rcTXts
XLFp8ExrJ91dWNQPc4PaGfBjUYAf+dYcFenaZNyrN7umHW6TotxPpmGqwDvX
E8cCMO51oof9Z6id0MPxDdwO/DVahkN+7N1HtZ0MDBFt59rdMZrOABmCq0xH
mpTOl5tODeC5RkyPdD/M/UX39oC1X3LiDsv7Vmwg33YxDoCdr+xs+8UYdMGl
d/8+lC9N+WC60x0zt3oP9NXC1rIGNtU1qXuJ8LI39o54YZVPfpINYqkgYN+B
XZ1aW6KPBi/uKw12FGuc/ltadG4WVZ0YeWjuUzMXr30SdE0H57+GMx4kRdqx
5t254nV4A+WDwguGG5hlfOi+kmHDpZsP69BzHMa/oQpG1cHfCRhNVdEjgBE4
WN3h0pkpFRF5HFXZVnlDa6sHtDeqoMp6BVAjX1Vj14R5Fj8DHS+svvCfWo8B
oUNqYTXmhfKhOnjEZq+/7M0fxdkznpRsm/x6qcEq4MtO5ZMWR/Ph6lnnOLzX
F0wml3f1kmgBGfr+ftGS5tLheXjPEd4P9loMef+8w+4H2KjdlTb4VXjgzJ+/
6CxkJZ7SXFa95bidA8UOBxAbN96NNo5he+yuaOu9hjf1XYjbDk1cSZvLQX7h
riIlP6sw+WOjuTkIPo3Cw0xcyz32a2W8o0ZlAeQrkdAzqU0Vl0AafHJNaWro
B7ruDdJ/bjnj0a5rPjbUoVj8y6he0sEE7QG7MZ2um+x1lBPrqNQOGanRyQux
+uyzgUliyDlojj3L/q/bY99zeAZ5v9V+8Vir9fZold+xQyMfsA3S3eQ+u/So
LYZDn3fscjqwRf+8B43RqGU+/P7E5ZfMNBsnZ/fz9Z/fP3l2evrnD+LSZi8m
V4jsjMhmDKOJUQNsVfzyylUFbnH/mtY9DdL9K1zKKdyWxNOHyL4XI9VEb0Fb
T86fRcZa2NxNFI5ewcdnT8036nq/4vdAUB8g2veUGX4J5QNkUQla6g1XSsdQ
WpszIcV3cEaVF1mx2YuPx7n59CkILgp6qyA9CuCUOJFS2ErAB2FrrNi0cQcF
VG4qR+btMPswUCX2501/l15p0AReRj9yy4Kn46C/r4CixvXQ+QFU2nk0w2Wm
IdkjZD46N6zJo8Jv6BuoSnrn3S23D7aQfO5kVRkvW2+hXt1sbTPZPiEM6X4X
RAPnnNydzkQYhlCxvJ5G2AjGUZm7yznyXHybRi9eIu6b1QW+8OGEOTL1NozR
RyZj3j911tP1gH26xW8Fc6gQqYdPV/USUlPxqB3ojL3bpogqd7OALnYiHLY9
KLyYAeofP/7s7cWr56dPvvj0aeY9AAwRbeZdF4gLFe/ka6oLLC66Agkw0EJJ
vJlLgE1sPlJPAGVF2rLGGMmkLOBEnUOYV2J6CF5BU5F4vEYEzREB5ilYbgKJ
EWrnrUIiVTah/4GNnE1ajC8Jb0tibDo9Ec+pHRIZE458rsqK3o/RpY95wFnb
xxYtpEG0ttXTP5htJNkGSzckY1iMzPdoNnJw8609OhZAu5kpbGoTG0Hbd0bT
+6j3Ng5khD0Ks7oVAjUk6LmURYwBncaUvMmKUcdgtWm499sKQrwclOt4p8LO
tJ3F4ncd5/uyDMdi1yMYoczIt2Q4LWrVvG4bUZPpdBo5XiG4EHMvxBllAJv8
1Kom3E8x/J8CZcD5uVnQdjv4XhRXz8QTBAsPQLwdHmXarZgMx7pb3yzNmNeX
MGP/ZmPCrJ513vB0H+8MvfJn2nO9vFFfUZZut3MI0iNRnz9/evJ86nocdKfK
BJVt9hmIn3GCMNJ09Z2Y+R3KDX52wwHGuYuBy+vYnsI2nwuAnzwFWDl4GrCD
ngpcv/ff04Fd3lUCNdN7LBhpdQzbdazvl9dBvzL1ahgfcjYlG8Pcf6UXRg9f
tNqwHsiB4MmfPeXWaCprSlPsda3X8Qw9iSiURRVjU9xw5gmkg0Vsio/0w4e2
SF3uaTf1N3II4xKd+sTFVkMdPB+HhUl3O5QwPZVexck1vXyDOsY8ytHBxwX7
LZm+OFrH4ECO8GEOzuDWUPsmgh6ixDf4FyrYW378ywiInHuK8aZsw8JIQpCG
OEzoR8m+pwukOfyHqYwsO00+ovJhYv8Aw/y5SlLsTh73ty8nUI1K/Mua/KQs
khNzrGkY/At6FdkQsDQAAA==

-->

</rfc>
