<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>
<?xml-stylesheet type="text/xsl" href="rfc2629.xslt" ?>
<!-- generated by https://github.com/cabo/kramdown-rfc version 1.7.30 (Ruby 3.4.8) -->
<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-irtf-cfrg-fiat-shamir-02" category="info" consensus="true" submissionType="IETF" tocInclude="true" sortRefs="true" symRefs="true" version="3">
  <!-- xml2rfc v2v3 conversion 3.31.0 -->
  <front>
    <title>Fiat-Shamir Transformation</title>
    <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-fiat-shamir-02"/>
    <author fullname="Michele Orrù">
      <organization>CNRS</organization>
      <address>
        <email>m@orru.net</email>
      </address>
    </author>
    <date year="2026" month="March" day="02"/>
    <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 duplex sponge object.</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 duplex sponge's internal state, while the squeeze operation produces variable-length, unpredictable outputs. This interface can be instantiated with different constructions based on permutation or compression functions.</t>
      <t>This specification also defines codecs to securely map prover messages into the duplex sponge domain, from the duplex sponge domain into verifier messages.
It also establishes how the non-interactive argument string should be serialized.</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 46?>

<section anchor="introduction">
      <name>Introduction</name>
      <t>The Fiat-Shamir transformation is a technique that uses a duplex sponge to convert a public-coin interactive protocol between a prover and a verifier into a corresponding non-interactive argument.
The term "public-coin" here refers to interactive protocols where all verifier messages are essentially random values sent in the clear.
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>duplex sponge instantiation</em> 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="security-considerations">
      <name>Security Considerations</name>
      <t>The Fiat-Shamir transformation carries over the soundness and witness hiding properties of the interactive proof:</t>
      <ul spacing="normal">
        <li>
          <t><strong>Completeness</strong>: If the statement being proved is true, an honest verifier can be convinced of this fact by an honest prover via the proof.</t>
        </li>
        <li>
          <t><strong>Soundness</strong>: If the interactive proof is sound, then so is the non-interactive proof. In particular, valid proofs cannot be generated without possession of the corresponding witness.</t>
        </li>
        <li>
          <t><strong>Zero-Knowledge</strong>: If the interactive proof is honest-verifier zero-knowledge, then so is the non-interactive proof. In particular, the resulting argument string does not reveal any information beyond what can be directly inferred from the statement being valid. This ensures that verifiers gain no knowledge about the witness.</t>
        </li>
      </ul>
      <t>In particular, the Fiat-Shamir transformation of Sigma Protocols is a zero-knowledge and sound argument of knowledge.</t>
      <t>Note that non-interactive Sigma Protocols do not have deniability, as the non-interactive nature of the protocol implies transferable message authenticity.</t>
    </section>
    <section anchor="the-duplex-sponge-interface">
      <name>The Duplex Sponge Interface</name>
      <t>The duplex sponge interface defines the space (the <tt>Unit</tt>) where the duplex sponge operates, plus a function for absorbing and squeezing prover messages. It provides the following interface.</t>
      <artwork><![CDATA[
class DuplexSponge:
  def init(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 64-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 duplex 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 duplex 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 is a collection of:
- functions that map prover messages into <tt>Unit</tt>s,
- functions that map <tt>Unit</tt>s into verifier messages, preserving the uniform distribution</t>
      <t>A codec provides the following interface.</t>
      <artwork><![CDATA[
class Codec:
    def prover_message(self, state, elements)
    def verifier_challenge(self, state) -> verifier_challenge
]]></artwork>
      <t>Where:</t>
      <ul spacing="normal">
        <li>
          <t><tt>prover_message(self, state, elements)</tt> denotes the absorb operation of the codec. This function takes as input the duplex sponge, and elements with which to mutate the duplex sponge.</t>
        </li>
        <li>
          <t><tt>verifier_challenge(self, state) -&gt; verifier_challenge</tt> denotes the squeeze operation of the codec. This function takes as input the duplex sponge to produce an unpredictable verifier challenge <tt>verifier_challenge</tt>.</t>
        </li>
      </ul>
      <t>The <tt>verifier_challenge</tt> function must generate a challenge from the underlying scalar field that is statistically close to uniform, from the public inputs given to the verifier, as described in <xref target="decode-random-bytes-scalars"/>.</t>
    </section>
    <section anchor="initialization-of-the-duplex-sponge-state">
      <name>Initialization of the Duplex Sponge State</name>
      <t>The duplex sponge state is initialized by sequentially absorbing:</t>
      <ul spacing="normal">
        <li>
          <t>A <tt>protocol_id</tt>: the unique identifier for the interactive protocol and the associated relation being proven. This identifier MUST be 64 bytes.</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). This identifier is currently generated as 32 zero-bytes concatenated with a 32-byte digest derived using the duplex sponge.</t>
        </li>
        <li>
          <t>An <tt>instance_label</tt>: the instance identifier for the statement being proven.</t>
        </li>
      </ul>
      <t>The <tt>session_id</tt> is computed as:</t>
      <artwork><![CDATA[
state = DuplexSponge.init(b"fiat-shamir/session-id".ljust(64, b"\x00"))
state.absorb(session)
session_id = [0] * 32 || state.squeeze(32)
]]></artwork>
      <t>The protocol instance label is absorbed without an explicit length prefix.
Therefore, the encoding used to produce <tt>instance_label</tt> MUST be prefix-free.</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 parameterized by:</t>
      <ul spacing="normal">
        <li>
          <t>a <tt>SigmaProtocol</tt>, which specifies an interactive 3-message protocol as defined in <xref section="2" sectionFormat="of" target="SIGMA"/>;</t>
        </li>
        <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>DuplexSpongeInterface</tt>, which specifies a duplex sponge for computing challenges.</t>
        </li>
      </ul>
      <t>Upon initialization, the protocol receives as input:
- <tt>session</tt>, which identifies the session being proven
- <tt>instance</tt>, the sigma protocol instance for proving or verifying</t>
      <artwork><![CDATA[
class NISigmaProtocol:
    Protocol: SigmaProtocol = None
    Codec: Codec = None
    DuplexSponge: DuplexSpongeInterface = None

    def __init__(self, session, instance):
        protocol_id = self.get_protocol_id()
        assert len(protocol_id) == 64
        self.sigma_protocol = self.Protocol(instance)
        self.codec = self.Codec()
        instance_label = self.sigma_protocol.get_instance_label()
        session_state = self.DuplexSponge(b"fiat-shamir/session-id".ljust(64, b"\x00"))
        session_state.absorb(session)
        session_id = [0] * 32 || session_state.squeeze(32)
        self.state = self.DuplexSponge(protocol_id)
        self.state.absorb(session_id)
        self.state.absorb(instance_label)

    def _prove(self, witness, rng):
        # Core proving logic that returns commitment, challenge, and response.
        # The challenge is generated via the duplex sponge.
        (prover_state, commitment) = self.sigma_protocol.prover_commit(witness, rng)
        self.codec.prover_message(self.state, commitment)
        challenge = self.codec.verifier_challenge(self.state)
        response = self.sigma_protocol.prover_response(prover_state, challenge)
        return (commitment, challenge, response)

    def prove(self, witness, rng):
        # Default proving method using challenge-response format.
        (commitment, challenge, response) = self._prove(witness, rng)
        assert self.sigma_protocol.verifier(commitment, challenge, response)
        return self.sigma_protocol.serialize_challenge(challenge) + self.sigma_protocol.serialize_response(response)

    def verify(self, proof):
        # Before running the sigma protocol verifier, one must also check that:
        # - the proof length is exactly Nc + response_bytes_len,
        Nc = self.sigma_protocol.instance.Domain.scalar_byte_length()
        assert len(proof) == Nc + self.sigma_protocol.instance.response_bytes_len

        # - proof deserialization successfully produces a valid challenge and a valid response,
        challenge_bytes = proof[:Nc]
        response_bytes = proof[Nc:]
        challenge = self.sigma_protocol.deserialize_challenge(challenge_bytes)
        response = self.sigma_protocol.deserialize_response(response_bytes)
        commitment = self.sigma_protocol.simulate_commitment(response, challenge)

        # - the re-computed challenge equals the serialized challenge.
        self.codec.prover_message(self.state, commitment)
        expected_challenge = self.codec.verifier_challenge(self.state)
        if challenge != expected_challenge:
            return False

        return self.sigma_protocol.verifier(commitment, challenge, response)

    def prove_batchable(self, witness, rng):
        # Proving method using commitment-response format.
        # Allows for batching.
        (commitment, challenge, response) = self._prove(witness, rng)
        # running the verifier here is just a sanity check
        assert self.sigma_protocol.verifier(commitment, challenge, response)
        return self.sigma_protocol.serialize_commitment(commitment) + self.sigma_protocol.serialize_response(response)

    def verify_batchable(self, proof):
        # Before running the sigma protocol verifier, one must also check that:
        # - the proof length is exactly commit_bytes_len + response_bytes_len
        assert len(proof) == self.sigma_protocol.instance.commit_bytes_len + self.sigma_protocol.instance.response_bytes_len

        # - proof deserialization successfully produces a valid commitment and a valid response
        commitment_bytes = proof[:self.sigma_protocol.instance.commit_bytes_len]
        response_bytes = proof[self.sigma_protocol.instance.commit_bytes_len:]
        commitment = self.sigma_protocol.deserialize_commitment(commitment_bytes)
        response = self.sigma_protocol.deserialize_response(response_bytes)

        self.codec.prover_message(self.state, commitment)
        challenge = self.codec.verifier_challenge(self.state)
        return self.sigma_protocol.verifier(commitment, challenge, response)
]]></artwork>
      <t>Serialization and deserialization of scalars and group elements are defined by the ciphersuite chosen in the Sigma Protocol. In particular, <tt>serialize_challenge</tt>, <tt>deserialize_challenge</tt>, <tt>serialize_response</tt>, and <tt>deserialize_response</tt> call into the scalar <tt>serialize</tt> and <tt>deserialize</tt> functions. Likewise, <tt>serialize_commitment</tt> and <tt>deserialize_commitment</tt> call into the group element <tt>serialize</tt> and <tt>deserialize</tt> functions.</t>
      <section anchor="nisigmaprotocol-instances-ciphersuites">
        <name>NISigmaProtocol instances (ciphersuites)</name>
        <t>We describe noninteractive sigma protocol instances for combinations of protocols (SigmaProtocol), codec (Codec), and duplex sponge (DuplexSpongeInterface). Descriptions of codecs and duplex sponge interfaces are in the following sections.</t>
        <artwork><![CDATA[
class NISchnorrProofShake128P256(NISigmaProtocol):
    Protocol = SchnorrProof
    Codec = P256Codec
    DuplexSponge = SHAKE128

class NISchnorrProofShake128Bls12381(NISigmaProtocol):
    Protocol = SchnorrProof
    Codec = Bls12381Codec
    DuplexSponge = SHAKE128

class NISchnorrProofKeccakDuplexSpongeBls12381(NISigmaProtocol):
    Protocol = SchnorrProof
    Codec = Bls12381Codec
    DuplexSponge = KeccakDuplexSponge
]]></artwork>
      </section>
    </section>
    <section anchor="group-prove">
      <name>Codec for Schnorr proofs</name>
      <t>We describe a codec for Schnorr proofs over groups of prime order <tt>p</tt> where <tt>Unit = u8</tt>.</t>
      <artwork><![CDATA[
class ByteSchnorrCodec(Codec):
    GG: groups.Group = None

    def prover_message(self, elements: list):
        state.absorb(self.GG.serialize(elements))

    def verifier_challenge(self, state):
        # see https://eprint.iacr.org/2025/536.pdf, Appendix C.
        Ns = self.GG.ScalarField.scalar_byte_length()
        uniform_bytes = state.squeeze(
            Ns + 16
        )
        scalar = OS2IP(uniform_bytes) % self.GG.ScalarField.order
        return scalar
]]></artwork>
      <t>We describe a codec for the P256 curve.</t>
      <artwork><![CDATA[
class P256Codec(ByteSchnorrCodec):
    GG = groups.GroupP256()
]]></artwork>
    </section>
    <section anchor="duplex-sponge-interfaces">
      <name>Duplex Sponge Interfaces</name>
      <section anchor="shake128">
        <name>SHAKE128</name>
        <t>SHAKE128 is a variable-length extendable-output function based on the Keccak sponge construction <xref target="SHA3"/>.
It belongs to the SHA-3 family and is used here to provide a duplex sponge interface.</t>
        <section anchor="initialization">
          <name>Initialization</name>
          <artwork><![CDATA[
new(self, iv)

Inputs:

- iv, a byte array

Outputs:

-  a duplex sponge instance

1. initial_block = iv + b'\00' * 104  # len(iv) + 104 == SHAKE128 rate
2. self.state = hashlib.shake_128()
3. self.state.update(initial_block)
]]></artwork>
        </section>
        <section anchor="shake128-absorb">
          <name>SHAKE128 Absorb</name>
          <artwork><![CDATA[
absorb(state, x)

Inputs:

- state, a duplex sponge state
- x, a byte array

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

Inputs:

- state, the duplex sponge state
- length, the number of elements to be squeezed

1. return self.state.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 64-byte initialization vector.</t>
          <artwork><![CDATA[
new(iv)

Inputs:
- iv, a 64-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>OS2IP</tt> and <tt>I2OSP</tt>: Convert a byte string to and from a non-negative integer, as described in
<xref target="RFC8017"/>. 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:

Ng, the number of bytes to represent an element in the coordinate field, equal to `ceil(log2(field.order())/8)`.

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

Inputs:

- state, the duplex sponge
- scalars, a list of elements of the elliptic curve's scalar field

Constants:

- Ns, the number of bytes to represent a scalar element, equal to `ceil(log2(p)/8)`.

1. for scalar in scalars:
2.     state.absorb(I2OSP(scalar, Ns))
]]></artwork>
        </section>
        <section anchor="absorb-elements">
          <name>Absorb elements</name>
          <artwork><![CDATA[
absorb_elements(state, elements)

Inputs:

- state, the duplex sponge
- elements, a list of group elements

1. for element in elements:
2.     state.absorb(ecpoint_to_bytes(element))
]]></artwork>
        </section>
        <section anchor="decode-random-bytes-scalars">
          <name>Decoding random bytes as scalars</name>
          <t>Given <tt>Ns + 16</tt> bytes, it is possible to generate a scalar modulo <tt>p</tt> that is statistically close to uniform.
Interpret the bytes as a big-endian integer, then reduce it modulo <tt>p</tt>, where <tt>p</tt> is the order of the group.</t>
          <artwork><![CDATA[
squeeze_scalars(state, length)

Inputs:

- state, the duplex sponge
- length, an unsigned integer of 64 bits determining the number of scalars to output.

Constants:

- Ns, the number of bytes to represent a scalar, equal to `ceil(log2(p)/8)`.

1. for i in range(length):
2.     scalar_bytes = state.squeeze(Ns + 16)
3.     scalars.append(OS2IP(scalar_bytes) % p)
]]></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="SIGMA">
          <front>
            <title>Interactive Sigma Proofs</title>
            <author fullname="Michele Orrù" initials="M." surname="Orrù">
              <organization>CNRS</organization>
            </author>
            <author fullname="Cathie Yun" initials="C." surname="Yun">
              <organization>Apple, Inc.</organization>
            </author>
            <date day="8" month="August" year="2025"/>
            <abstract>
              <t>   This document describes interactive sigma protocols, a class of
   secure, general-purpose zero-knowledge proofs of knowledge consisting
   of three moves: commitment, challenge, and response.  Concretely, the
   protocol allows one to prove knowledge of a secret witness without
   revealing any information about it.

              </t>
            </abstract>
          </front>
          <seriesInfo name="Internet-Draft" value="draft-irtf-cfrg-sigma-protocols-00"/>
        </reference>
        <reference anchor="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 455?>

<section anchor="test-vectors">
      <name>Test Vectors</name>
      <section anchor="testkeccakduplexspongeshake128">
        <name>test_keccak_duplex_sponge_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:6261736963206475706c65782073706f6e67652074657374
Operation2 = squeeze:64
Expected = f845c3ef4231a4d6e09c29b1eea0055842246fd57558fd7d93e1302f7
799dd9593d2e4d06eda72d5252ca5b2feff4b8cb324ec96673a7417cf70fa77b1898
991
]]></artwork>
      </section>
      <section anchor="testabsorbemptybeforedoesnotbreakshake128">
        <name>test_absorb_empty_before_does_not_break_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:656d707479206d657373616765206166746572
Operation2 = absorb:
Operation3 = squeeze:64
Expected = 3953e577d9e5d4dc7b86d1a62e881f2d1eb750ea3550fcae315854d16
6136ae816ca922a4c7e54d711b8721c8969598449922122768c50313f47eef35020b
73c
]]></artwork>
      </section>
      <section anchor="testabsorbemptyafterdoesnotbreakshake128">
        <name>test_absorb_empty_after_does_not_break_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:
Operation2 = absorb:656d707479206d657373616765206265666f7265
Operation3 = squeeze:64
Expected = 6e475edd3c400bec314d5891af570841a547c95d1a651adff9a8bfb70
719a79b5afde316386da13fa83525662df3c5b2367d987bf3dc4199efdb9d0612572
785
]]></artwork>
      </section>
      <section anchor="testsqueezezerobehaviorshake128">
        <name>test_squeeze_zero_behavior_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = squeeze:0
Operation2 = absorb:7a65726f2073717565657a652074657374
Operation3 = squeeze:0
Operation4 = squeeze:64
Expected = 4cf7f008057b63cb615547a143f42cf793b86b239f404d2f28b3f0919
7d850eb029df3024ad468be5aceb2fa60e9fb7add98436236be69ddb34314ce7a905
f23
]]></artwork>
      </section>
      <section anchor="testsqueezezeroafterbehaviorshake128">
        <name>test_squeeze_zero_after_behavior_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = squeeze:0
Operation2 = absorb:7a65726f2073717565657a65206166746572
Operation3 = squeeze:64
Expected = bd9278e6f65cb854935b3f6b2c51ab158be8ea09744509519b8f06f0c
501d07c429e37f232b6f0955b620ff6226d9d02e4817b1447e7309023a3a14f73587
6ec
]]></artwork>
      </section>
      <section anchor="testabsorbsqueezeabsorbconsistencyshake128">
        <name>test_absorb_squeeze_absorb_consistency_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 656467652d636173652d746573742d646f6d61696e2d6162736f72620000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:696e7465726c65617665206669727374
Operation2 = squeeze:32
Operation3 = absorb:696e7465726c65617665207365636f6e64
Operation4 = squeeze:32
Expected = 4d31a75f29851f9f15cd54fa6f2335cbe07b947b9d3c28092c1ba7315
e295921
]]></artwork>
      </section>
      <section anchor="testassociativityofabsorbshake128">
        <name>test_associativity_of_absorb_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 6162736f72622d6173736f6369617469766974792d646f6d61696e000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:6173736f63696174697669747920746573742066756c6c
Operation2 = squeeze:32
Expected = c0faa351141d60678dceff4f3a5760381bb335ad113958b70edf7b242
df01c8a
]]></artwork>
      </section>
      <section anchor="testivaffectsoutputshake128">
        <name>test_iv_affects_output_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 646f6d61696e2d6f6e652d646966666572732d6865726500000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:697620646966666572656e63652074657374
Operation2 = squeeze:32
Expected = 7650642267cc544abf0e01ce28e2595aec4c2f5b5e5e3720ab5514496
37b35f2
]]></artwork>
      </section>
      <section anchor="testmultipleblocksabsorbsqueezeshake128">
        <name>test_multiple_blocks_absorb_squeeze_SHAKE128</name>
        <artwork><![CDATA[
DuplexSponge = SHAKE128
IV = 6d756c74692d626c6f636b2d6162736f72622d7465737400000000000000000
00000000000000000000000000000000000000000000000000000000000000000
Operation1 = absorb:abababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababababab
abababababababababababababababababababababababababababababababab
Operation2 = squeeze:600
Expected = 526d4f6cfca230e0654bf8749bddc0f4416a8a164c50f3c1b0bc1d527
2a88b9a524e73cafad76691a29c0e03a5255fd8fb9d778ef5a0c8c9e11e003011d25
6bf92dd36233e4c6c360baca0f8ac305d459adb1231a801742669efa051396e96417
814448b5328336d028a62dbddf24d1bb68496d27f1944eb24d4b2812d9ad4eae6c26
0b720c44ed2be8bfeeed3acc2640edbab987674f2cef8ceacda1e04f254170aba424
1dabc6364ed5afc09b58205682d5e8413bf5f9d97e9c799b97876ccd1c48d86759ad
e5871acc4c5d41d37f2b1843c8b6f9e0bade78342d56f9b1e8232d4c7553674d889e
69fe24dea31f42f0b02b70161876ceb12cc0b36868c262cbebb5e815a1eceaee97ae
d3402a518287c32f2f469c3a38a17afd0f0d82433acf695ae143ded9412b4e6b6144
bd6d4be6bb7de33c05f560480c63aa89336954f1cf5992399e6ed59d406adb4497bb
88aa897fd3d65646cf86e796da4f193c418a74d662f57e0e0c775386abdace02157e
519ba54495555145016c550ff32004981d0e34f0abe7d814ac4fe25260473ffa8746
0a736f20954e8d3b9f16140e79451953fe6cfc222cba6ad4f85a2e2efd6ff8f5fef6
5d8480e6af40baab298c4de57f30d08a5e1b4c10d123a5af7702ff26ba9a84a6fe92
f48391b23a7e8e8cb06deda74d1b10870611995f6bfe4df60320a0b7f2c891cad5a5
645ecec80868ed568591a74dafb35cabb42dae1a1085269b655db1ebf09929f63d5a
f775a24e43759f673b83aeefef382bc2b7bf175bb9d90e77911466ffb3b230754776
5cd5adc30a6b07881a88fd1511e5f8d2dcc4347c076e6c79676d8df
]]></artwork>
      </section>
    </section>
  </back>
  <!-- ##markdown-source:
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
FKe2+r1s5B+ps+6X96Tb6hqCqjQ6HazgNN5ppbjfzq6a0p104qmaPTCBtnyF
vMVT6TPrWi1aypEPu3rRUo00NfbTToNtPzsqp215YZm82zDq5fXJMN+jpHjR
E7+Ey4U61UDTtoOYi6GfdQbhJufbHlv4e4neU9uTQfm6coxw1vdyB9TBmtBz
X0/w+gAhbe2MZl/YLqmLeoAQ+PL6fFy0mJ2jcYmx0c9Mp0B//bhWgXmt5l6M
rpKN75Ade8RP2onbU8vMZbKyX7YfIhMDSi+5LIH9mOvguTyxruaVpqGo9d/T
4Xzc5FWcVcPAXtnaHfHXUDthsHloODxcCvsRLDaTxzye7gFOSBtpad/JPknc
SeegifxC6DsI+lcgdERv+w3J7x8/dIPIsr6SF5G2ukuswz7KW9mroGvpJV26
gsBG16S0cLTZ017Ah92GWluyeQPtUCGuR5aNg0AfbeTF9EbIKxXAZ1juwuw9
7PuMSm1LaIWWzJ8WH3OT+jHNt1nhIW+mteW1usggcSYE6GISOdCcLk8gAzJH
OgZDMaIBY1Qeuf5JjOzDjask3YM+XAvT7Zsq4LADcby/oBWlb8sOE9o1k3sd
Z2obYQyFdhH25+o3XzLG38ibqnSL6XeyOwX7oJzSpt/C2ryRmav+hY+N4vym
797/6U9/sk5t2L34Hb7FYSSiNA7CIg6iMPbjIPbDIsqiMPLx140yfEtjZMWL
f6wTzz/8j/W1SQhdoKPM+DLyIjf2ozTyPScK4jB2Ig7sEs8Bhk5UAOc4CvFN
4zwA8UgCiveXUWB9qU+04WmRBCH3RRF4vsuCPBJOyr00c4VgjhOGSeB5QVTk
YYzPRR7nqS9c3/GK2IrTNM/TMPVzTwS5E4mcxV4eeqHHWZh5hSiKIEt45nuB
4GkUxT6LAzfmRewULI4zN0kTK01dKY1Bcsa33u67+00mDzVt6JcgNsh1N1kj
INX/9XIMozyGlOIUcswlXoSLlB3+jSSu3lR6eurw0D8pUj8NfRHGkJUI8yDn
cZZEucsiTySJW3i5K7I4dATzw9ApOBO+GyZhkLuRFaGeYyJxI85Sz2MBjwVe
xK6bJbHn8iSNIO8kCFK8dT0vjhIeOr7rF0EsROGHjudkVuzzh0TKCni0/2sS
XZTVg2L28DaKihj/fohMIwF7F3nu88BxMsF9N8jDJHVZAS+QBC4Lg5inIYk5
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
AAA=

-->

</rfc>
