<?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 2.6.10) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-orru-zkproof-fiat-shamir-00" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.29.0 -->
  <front>
    <title>Fiat-Shamir Transformation</title>
    <seriesInfo name="Internet-Draft" value="draft-orru-zkproof-fiat-shamir-00"/>
    <author fullname="Michele Orrù">
      <organization>CNRS</organization>
      <address>
        <email>m@orru.net</email>
      </address>
    </author>
    <date year="2025" month="July" day="07"/>
    <workgroup>Zkproof</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-zkproof-sigma-protocols/draft-orru-zkproof-fiat-shamir.html"/>.
        Status information for this document may be found at <eref target="https://datatracker.ietf.org/doc/draft-orru-zkproof-fiat-shamir/"/>.
      </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/mmaker/draft-zkproof-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-zkproof-sigma-protocols/tree/main/poc/vectors">proof-of-concept implementation</eref>.</t>
    </section>
  </back>
  <!-- ##markdown-source:
H4sIAJZebGgAA9Vb627cuBX+r6fg2ih2pjsjO3aaTadIsWma7BrbZoM42wJN
g5FG4syw1khaUbI9GwToO/Rp+rtv0ifpuZCUKGlsby8/GiwWNkUeHp7znSvp
+Xwe1KrO5EIcvVJxPb/cxjtViXdVnOt1Ue3iWhX5UZDEtdwU1X4hVL4ugiAt
kjzewaq0itf1vKiqZv7jVVkVxXq+Rjqa6MxPTwPdrHZKayBT70tYcfHy3asg
b3YrWS2CFOgugqTItcx1oxeirhoZXC/EeXAs4krGC/H87cvnwU1RXW2qoikX
4k+8TXAl9zCaLgIxFz/KqhBXeXGTyXQjcWQb621wLfMGyAthlh69qPZlXYhX
RdXsjmCcOTrCH3exyuDHZF1tvlKyXodFtcHxuEq2ML6t61IvTk5wGg6paxna
aSc4cLKqihstT5AArtuoetusYOVuF1/J6oQFZWWk1WYXz+HnukiKTOOCDESh
6+5WtDBkQqEq7iZxcrcmwm29y46CIG7qbQGCn8OOQqybLGM9Hv1eJVuZSfFd
Vf3j70f0FY4W5+pHgsBCvHj99pKGpRHV7ivcLMxlDXRzxso1iDtAiLjfhLj8
5vn5glZapMHI/Fxc1nGexqBB8UZWu6amfea/ibVMxTegPgGfxcvbWsKsVSbn
3zV12dTiVZMnOFMzk3VcbSSIzUotv87KZqXDXOk63BTXJ/gDjpy8unhzefL6
4vJdiD+FZ6dnYZmug2A+n4t4pesqTuogeLdVWgC8m53Ma5FKnVRqJbXYFjcC
oINQBYwmtYhFDuyqvJa4EM4qSOjiWsWi3kqB5vTPv/7NGFTtGdRMNFrlG6Cx
kbmsVIJrE5k2lYS1cQ3b7EqVwbZxLoZbwEgxsn+RS7Hai0pmeyRe5DBHg1gl
qJkMQhSrv0hgnbYAUtcqxS1E2pSZvBW6LPKN5P3WcSJDlIY89BX2+aFRFRCo
bwqxk4CrFAwYJFlUK9Kd/qGR8kc5EzdbABfM16UkTjNkMk5p0k2laikAeShv
LeB0wDTMU2sFOFgBGshKQ4GsGOJFCWdGOQI3SUUr4wyINiX6E03iZ3Y/18xw
HhsJkDyIo0zyPGayQxMEkzYJkLmOK0XIy2S+qbegtLysZKqSGkdFQXjUyJnS
HbkkoLMVCgr2ymtAAZzjBoyY6BWNZkbWFsZ0xhS1VbZmALZHGACZoedsZ4cG
oUZECc+OM10AVtcqB7aTIpWJRrBqmTSIBnBuZSvidVXs6OiIAFkxmuqBotMC
7ByQikpyS8amMAGghCqrAAlaxxuJnKJl7VSaZjIAd36R1yRZ5JiR1Y04voEI
hbisZbLNFSiIEdtoQqsnPmOTsDtaJNh5ppJ5UqiB2ZCXBL3UN1KiYZjD4+ni
lnljWQl4NomHTNGQRuycqIXBBXqIEhwUADcHzzcXz3OxVLkCtWfGcwLxpC6q
pZhc/GEKEMLzgErA9AAca7JUowwiOmNUst5Z+jSAuCWXtJK4hNjPQ7fjkLul
0E1ZFlXNjmYNUoZtwb4cKcLISnZpiaUn3aVQu5JxY/k84A1mAPuSzWJtzBRX
qBxNpGemrW/AKT0r6xlZiybijrC9tB7F4RuIx6W2OnVId8gmNxJn5TYGALBQ
jfUiu6PHGkG0mKA9yurayQJCC0SHBkU1DRHjiOrfMqlLJnVhJRQEz3u7sMsB
ugaJLgqJ6HuAUESOj5h1vhp3XRdZVtywdFtPjbEwyWKtzf68Pcddgb5B5PJm
oiC1Wu1hz6mY/9qb2ZnI6ptoma1n4nYhMjjme+Tow7QzyzhOM42Vh+lhTaTb
NUHwx62sJFlHhKZxBxMRUM4L68J7dmRBaRxu6wEgTQK/oBlsAPXzszmS769n
OwQeriMSqvtsIwbaxSgeEHyRJ5XrOGuk9kTj8z6IVIauIXjfEZAuLjFAcIhG
vilGmG0iX3ou1tFZiO3DavIZHsbBn8Qx+9tNBXtHvEnUzQH0HWeCIWP6dqUz
pRdo7i3M0YTIA/w0gyAq1hIO2QJN8uawN1ka6zcC9Aen3gLrMJbJFvwcHIUX
Efnht/9PuyDxE7AeIh48B354mG0w7ftOYZy82aLPRzQwEaLazQNb2/hpCnug
vdxxirywARGZpHTmMIcYnE0qiublh0UXmxx3Y6dhQ/oaSwyPxQsfAH9gAHw8
VtfzjZv8iXO0cbBQembwBMkoREEKiZCkSSjsoQ6gXIiUw8mISqMF7c0JkE1/
8AiQ9BlYjyRsNv8BOy4SzqUh4jMvg0wIvB3nTe12ZqCz34w2BOFXc+NFUswg
a3lbNyB7V7xiWr2CLMGoiCZA3iErafM1rMQ05NapFBMZbkIQyfdvfzfD3B1y
VwWIrONdOTVJWsQFQSKXGWQhmeHPDo4J5FDOh2knVhw2NYMDgH2wF9TG82Ea
t2QcPfNcSUiu5v3pB/FzUOC0Nzk0Ue7i7LvLNxMA0aSjwelMPJ4eWtGddy/R
Vk130uxMM2XPjcowiRfytgRkSHRWYGQ11s0Af031FIG8XyKRJdxRb6DML7Gj
It7Yjgo4aOkaAMP6f7T610SIWjMOw6CS+4udMq5iqKEr8LpQ9e7JfmIRUVSK
XL5r6mLXjTCe1HeJ7F3MDOumhg5D/4q3oFPbQ49s1etAnM+t523LoOD7kmrx
rqeYeVUNGG0iYbmfMlDIAXU5R8J792skZfzkwClY4+6aB32cFCXygNXGFMbl
nNorGh2uLnbygJE7+tyc6Zqnl0+8vvBk1mYWbkR4E9x3TkRMquGlDmSUHEJd
FjBzu0/bLfAfzgs9A6cRIgtJxHQ4WZV2kuVp4mgHw6THcHKj6hyENhNVvumx
MDFR17RTkmK3UzX6oqndSJWhmcMfJx41j1gbw571zxb2sozORuFI9Pbpcgmv
5ZAl+6V/DEuoIxT8B0rH/oIlYjfucNNZO3P79rkBN5U7IkCRk6xlS6V7PPHF
yFTHd7vFMAPdt7lYse7prd1gyRb3jKe9X9jNHOJ5Kk9bwsk+jMq2R+ZeKosP
B/jpKCmV9wiHyd2r7C6dgeTGaPzvgOip/uH4CY6PTQ2EYeV3KpdxJajV8fGY
7jQohZGf/FAVmyKJYlqyzYuqstGJ4gStpDhZVpClQL6SwmhURpzBmWYmhVck
4ZXC2qRAVMSBmJqnkecbmcffx2Wv6Pqab2B465B+g9Wvi1y6KV7fwvvN9VDs
knt958M8ZncPcpz313+2auXS/+5twk7LgI/cmvLEEpr6UDkWCeBA2yYyoAIE
mh5C04j1j5QzPpMQXTH4OcPtM20bBt4idzo+xiUwGVevlMzSUNPPRG7J9fsE
ndejJx6BXlCiNbD5d5dnF28mHktT8bNDWxFQR2VBkzDFe6FKwKduFFAi87n8
5vm3Lx+dPQ0C+xMXL/22o99Vdj15TAK+lUkSX9muncsAcd7Hj3i79elTKC4w
S89gBnVVcRnfcpm+66rB3scaWMNeLKBOtVcIwt4veK0+5HSluD9CjU5V70W8
idG1AhMZ4I/Sl7qOkysMq3ITV2kGaLVlnkedrmugIpEppsLHx70ikJGEbRFr
ScYaLqhgXfAvcxgHNsnGRFxV8Z7H+WqunWW79Gxtnf4Nfn4Uii3ibgs18RJO
6VKWs9Dqc8ssOo09J0Pi5caoWsTOxO04r90pXYbM59uxkyBzId8jTW6nPTYu
2TR4prWT7i4s6vu5Qe0M+LEowI98P46KdG0y7tWbXdMOt0lR7ifTMFXgneuJ
YwEY9zrRw/4z1E7o4fgGbgf+Gi3DIT/27qPaTgaGiLZz7e4YTWeADMFVpiNN
SufLTacG8Fwjpke6H+b+ont7wNovOXGH5X0rNpBvuxgHwM5Xdrb9Ygy64NK7
fx/Kl6Z8MN3pjplbvXv6amFrWQOb6prUnUR42Rt7R7ywyic/yQaxVBCwb8Gu
Tq0t0UeDF/eVBjuKNU7/LS06N4uqTow8NPexmYvXPgm6poPzX8MZD5Ii7Vjz
7lzxOryB8kHhBcMNzDI+dF/JsOHSzYd16DkO499QBaPq4O8EjKaq6BHACBys
7nDpzJSKiDyOqmyrvKG11QPaG1VQZb0CqJGvqrFrwjyLz0DHC6sv/KfWY0Do
kFpYjXmhfKgOHrHZ6y9680dx9oQnJdsmv1pqsAr4slP5pMXRfLh61jkO7/Ul
k8nlbb0kWkCGvr9ftKS5dHga3nGE94O9FkPev+iw+wE2anelDX4ZHjjzF886
C1mJpzSXVW85budAscMBxMaNd6ONY9geuyvaeq/hTX0X4rZDE1fS5nKQX7ir
SMnPKkz+2GhuDoJPo/AwE1dyj/1aGe+oUVkA+Uok9C5qU8UlkAafXFOaGvqB
rnuD9J9bzni065qPDXUoFv8yqpd0MEF7wG5Mp+smex3lxDoqtUNGanTyTKw+
/3xgkhhyDppjz7L/6/bY9xyeQd5ttV8+1Gq9PVrld+zQyAdsg3Q3ucsuPWqL
4dAXHbucDmzRP+9BYzRqmQ+/P3L5JTPNxsnZ/Xz95/ePnpye/vmDuLDZi8kV
IjsjshnDaGLUAFsVv7xyVYFb3L+mdU+DdP8Kl3IKtyXx9CGy78VINdFb0Naj
8yeRsRY2dxOFoxfw8clj84263i/4PRDUB4j2PWWGL6F8gCwqQUu95krpGEpr
cyak+A7OqPIiKzZ78fE4N58+BcGrgt4qSI8COCVOpBS2EvBB2BorNm3cQQGV
m8qReTvMPgxUif1509+lVxo0gZfRj9yy4Ok46O8roKhxPXR+AJV2Hs1wmWlI
9giZj84Na/Ko8Bv6BqqS3nl3y+2DLSSfO1lVxsvWW6hXN1vbTLZPCEO63wXR
wDknt6czEYYhVCyvpxE2gnFU5u5yjjwX36bRi5eI+2Z1gS98OGGOTL0NY/SR
yZj3T531dD1gn27xW8EcKkTq4dNVvYTUVDxoBzpj77YposrdLKCLnQiHbQ8K
L2aA+sePn7199eLp6aMvP32aeQ8AQ0SbedcF4kLFO/ma6gKLi65AAgy0UBJv
5hJgE5uP1BNAWZG2rDFGMikLOFHnEOaVmB6CV9BUJB6vEUFzRIB5CpabQGKE
2nmrkEiVTeh/YCNnkxbjS8LbkhibTk/EU2qHRMaEI5+rsqL3Y3TpYx5w1vax
RQtpEK1t9fQPZhtJtsHSDckYFiPzPZqNHNx8a4+OBdBuZgqb2sRG0Pat0fQ+
6r2NAxlhj8KsboVADQl6LmURY0CnMSVvsmLUMVhtGu79toIQzwflOt6psDNt
Z7H4Xcf5rizDsdj1CEYoM/ItGU6LWjWv20bUZDqdRo5XCC7E3DNxRhnAJj+1
qgn3Uwz/p0AZcH5uFrTdDr4XxdUz8QjBwgMQb4dHmXYrJsOx7tY3SzPm9SXM
2L/ZmDCrZ503PN3HO0Ov/Ln2XC9v1FeUpdvtHIL0SNTnTx+fPJ26HgfdqTJB
ZZt9BuJnnCCMNF19J2Z+h3KDn91wgHHuYuDyOransM3nAuAnTwFWDp4G7KCn
Atfv/fd0YJd3lUDN9B4LRlodw3Yd67vlddCvTL0axoecTcnGMPdf6YXRwxet
NqwHciB48iePuTWayprSFHtd63U8Q08iCmVRxdgUN5x5AulgEZviI/3woS1S
l3vaTf2NHMK4RKc+cbHVUAfPx2Fh0t0OJUxPpVdxckUv36COMY9ydPBxwX5L
ps+O1jE4kCN8mIMzuDXUvomghyjxNf6BCvaWH/4yAiLnnmK8KduwMJIQpCEO
E/pRsu/5L0rgP0xlZNlp8hGVDxP7Bxjm71WSYnfykD99OYFaVOKf1eQnZZGc
mENNw+BfANzaYZs0AAA=

-->

</rfc>
