



Crypto Forum                                                     M. Orrù
Internet-Draft                                                      CNRS
Intended status: Informational                              2 March 2026
Expires: 3 September 2026


                       Fiat-Shamir Transformation
                     draft-irtf-cfrg-fiat-shamir-02

Abstract

   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.

   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.

   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.

About This Document

   This note is to be removed before publishing as an RFC.

   The latest revision of this draft can be found at
   https://mmaker.github.io/draft-irtf-cfrg-sigma-protocols/draft-irtf-
   cfrg-fiat-shamir.html.  Status information for this document may be
   found at https://datatracker.ietf.org/doc/draft-irtf-cfrg-fiat-
   shamir/.

   Discussion of this document takes place on the Crypto Forum Research
   Group mailing list (mailto:cfrg@ietf.org), which is archived at
   https://mailarchive.ietf.org/arch/browse/cfrg.  Subscribe at
   https://www.ietf.org/mailman/listinfo/cfrg/.

   Source for this draft and an issue tracker can be found at
   https://github.com/mmaker/draft-irtf-cfrg-sigma-protocols.





Orrù                    Expires 3 September 2026                [Page 1]

Internet-Draft         Fiat-Shamir Transformation             March 2026


Status of This Memo

   This Internet-Draft is submitted in full conformance with the
   provisions of BCP 78 and BCP 79.

   Internet-Drafts are working documents of the Internet Engineering
   Task Force (IETF).  Note that other groups may also distribute
   working documents as Internet-Drafts.  The list of current Internet-
   Drafts is at https://datatracker.ietf.org/drafts/current/.

   Internet-Drafts are draft documents valid for a maximum of six months
   and may be updated, replaced, or obsoleted by other documents at any
   time.  It is inappropriate to use Internet-Drafts as reference
   material or to cite them other than as "work in progress."

   This Internet-Draft will expire on 3 September 2026.

Copyright Notice

   Copyright (c) 2026 IETF Trust and the persons identified as the
   document authors.  All rights reserved.

   This document is subject to BCP 78 and the IETF Trust's Legal
   Provisions Relating to IETF Documents (https://trustee.ietf.org/
   license-info) in effect on the date of publication of this document.
   Please review these documents carefully, as they describe your rights
   and restrictions with respect to this document.  Code Components
   extracted from this document must include Revised BSD License text as
   described in Section 4.e of the Trust Legal Provisions and are
   provided without warranty as described in the Revised BSD License.

Table of Contents

   1.  Introduction  . . . . . . . . . . . . . . . . . . . . . . . .   3
   2.  Security Considerations . . . . . . . . . . . . . . . . . . .   4
   3.  The Duplex Sponge Interface . . . . . . . . . . . . . . . . .   4
   4.  The Codec interface . . . . . . . . . . . . . . . . . . . . .   5
   5.  Initialization of the Duplex Sponge State . . . . . . . . . .   5
   6.  Fiat-Shamir transformation for Sigma Protocols  . . . . . . .   6
     6.1.  NISigmaProtocol instances (ciphersuites)  . . . . . . . .   8
   7.  Codec for Schnorr proofs  . . . . . . . . . . . . . . . . . .   8
   8.  Duplex Sponge Interfaces  . . . . . . . . . . . . . . . . . .   9
     8.1.  SHAKE128  . . . . . . . . . . . . . . . . . . . . . . . .   9
       8.1.1.  Initialization  . . . . . . . . . . . . . . . . . . .   9
       8.1.2.  SHAKE128 Absorb . . . . . . . . . . . . . . . . . . .   9
       8.1.3.  SHAKE128 Squeeze  . . . . . . . . . . . . . . . . . .  10
     8.2.  Duplex Sponge . . . . . . . . . . . . . . . . . . . . . .  10
       8.2.1.  Initialization  . . . . . . . . . . . . . . . . . . .  10



Orrù                    Expires 3 September 2026                [Page 2]

Internet-Draft         Fiat-Shamir Transformation             March 2026


       8.2.2.  Absorb  . . . . . . . . . . . . . . . . . . . . . . .  10
       8.2.3.  Squeeze . . . . . . . . . . . . . . . . . . . . . . .  11
       8.2.4.  Keccak-f[1600] Implementation . . . . . . . . . . . .  12
   9.  Codecs registry . . . . . . . . . . . . . . . . . . . . . . .  12
     9.1.  Elliptic curves . . . . . . . . . . . . . . . . . . . . .  12
       9.1.1.  Notation and Terminology  . . . . . . . . . . . . . .  12
       9.1.2.  Absorb scalars  . . . . . . . . . . . . . . . . . . .  13
       9.1.3.  Absorb elements . . . . . . . . . . . . . . . . . . .  13
       9.1.4.  Decoding random bytes as scalars  . . . . . . . . . .  13
   10. References  . . . . . . . . . . . . . . . . . . . . . . . . .  14
     10.1.  Normative References . . . . . . . . . . . . . . . . . .  14
     10.2.  Informative References . . . . . . . . . . . . . . . . .  14
   Appendix A.  Test Vectors . . . . . . . . . . . . . . . . . . . .  14
     A.1.  test_keccak_duplex_sponge_SHAKE128  . . . . . . . . . . .  14
     A.2.  test_absorb_empty_before_does_not_break_SHAKE128  . . . .  15
     A.3.  test_absorb_empty_after_does_not_break_SHAKE128 . . . . .  15
     A.4.  test_squeeze_zero_behavior_SHAKE128 . . . . . . . . . . .  15
     A.5.  test_squeeze_zero_after_behavior_SHAKE128 . . . . . . . .  15
     A.6.  test_absorb_squeeze_absorb_consistency_SHAKE128 . . . . .  16
     A.7.  test_associativity_of_absorb_SHAKE128 . . . . . . . . . .  16
     A.8.  test_iv_affects_output_SHAKE128 . . . . . . . . . . . . .  16
     A.9.  test_multiple_blocks_absorb_squeeze_SHAKE128  . . . . . .  16
   Author's Address  . . . . . . . . . . . . . . . . . . . . . . . .  17

1.  Introduction

   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:

   *  An _initialization vector_ (IV) uniquely identifying the protocol,
      the session, and the statement being proven.

   *  An _interactive protocol_ supporting a family of statements to be
      proven.

   *  A _duplex sponge instantiation_ capable of absorbing inputs
      incrementally and squeezing variable-length unpredictable
      messages.

   *  A _codec_, which securely remaps prover elements into the base
      alphabet, and outputs of the duplex sponge into verifier messages
      (preserving the distribution).





Orrù                    Expires 3 September 2026                [Page 3]

Internet-Draft         Fiat-Shamir Transformation             March 2026


2.  Security Considerations

   The Fiat-Shamir transformation carries over the soundness and witness
   hiding properties of the interactive proof:

   *  *Completeness*: If the statement being proved is true, an honest
      verifier can be convinced of this fact by an honest prover via the
      proof.

   *  *Soundness*: 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.

   *  *Zero-Knowledge*: 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.

   In particular, the Fiat-Shamir transformation of Sigma Protocols is a
   zero-knowledge and sound argument of knowledge.

   Note that non-interactive Sigma Protocols do not have deniability, as
   the non-interactive nature of the protocol implies transferable
   message authenticity.

3.  The Duplex Sponge Interface

   The duplex sponge interface defines the space (the Unit) where the
   duplex sponge operates, plus a function for absorbing and squeezing
   prover messages.  It provides the following interface.

   class DuplexSponge:
     def init(iv: bytes) -> DuplexSponge
     def absorb(self, x: list[Unit])
     def squeeze(self, length: int) -> list[Unit]

   Where:

   *  init(iv: bytes) -> DuplexSponge denotes the initialization
      function.  This function takes as input a 64-byte initialization
      vector iv and initializes the state of the duplex sponge.

   *  absorb(self, values: list[Unit]) denotes the absorb operation of
      the duplex sponge.  This function takes as input a list of Unit
      elements and mutates the DuplexSponge internal state.




Orrù                    Expires 3 September 2026                [Page 4]

Internet-Draft         Fiat-Shamir Transformation             March 2026


   *  squeeze(self, length: int) denotes the squeeze operation of the
      duplex sponge.  This function takes as input an integral length
      and squeezes a list of Unit elements of length length.

4.  The Codec interface

   A codec is a collection of: - functions that map prover messages into
   Units, - functions that map Units into verifier messages, preserving
   the uniform distribution

   A codec provides the following interface.

   class Codec:
       def prover_message(self, state, elements)
       def verifier_challenge(self, state) -> verifier_challenge

   Where:

   *  prover_message(self, state, elements) denotes the absorb operation
      of the codec.  This function takes as input the duplex sponge, and
      elements with which to mutate the duplex sponge.

   *  verifier_challenge(self, state) -> verifier_challenge denotes the
      squeeze operation of the codec.  This function takes as input the
      duplex sponge to produce an unpredictable verifier challenge
      verifier_challenge.

   The verifier_challenge 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
   Section 9.1.4.

5.  Initialization of the Duplex Sponge State

   The duplex sponge state is initialized by sequentially absorbing:

   *  A protocol_id: the unique identifier for the interactive protocol
      and the associated relation being proven.  This identifier MUST be
      64 bytes.

   *  A session_id: 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.

   *  An instance_label: the instance identifier for the statement being
      proven.



Orrù                    Expires 3 September 2026                [Page 5]

Internet-Draft         Fiat-Shamir Transformation             March 2026


   The session_id is computed as:

 state = DuplexSponge.init(b"fiat-shamir/session-id".ljust(64, b"\x00"))
 state.absorb(session)
 session_id = [0] * 32 || state.squeeze(32)

   The protocol instance label is absorbed without an explicit length
   prefix.  Therefore, the encoding used to produce instance_label MUST
   be prefix-free.

6.  Fiat-Shamir transformation for Sigma Protocols

   We describe how to construct non-interactive proofs for sigma
   protocols.  The Fiat-Shamir transformation is parameterized by:

   *  a SigmaProtocol, which specifies an interactive 3-message protocol
      as defined in Section 2 of [SIGMA];

   *  a Codec, which specifies how to absorb prover messages and how to
      squeeze verifier challenges;

   *  a DuplexSpongeInterface, which specifies a duplex sponge for
      computing challenges.

   Upon initialization, the protocol receives as input: - session, which
   identifies the session being proven - instance, the sigma protocol
   instance for proving or verifying

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.



Orrù                    Expires 3 September 2026                [Page 6]

Internet-Draft         Fiat-Shamir Transformation             March 2026


        # 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



Orrù                    Expires 3 September 2026                [Page 7]

Internet-Draft         Fiat-Shamir Transformation             March 2026


        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)

   Serialization and deserialization of scalars and group elements are
   defined by the ciphersuite chosen in the Sigma Protocol.  In
   particular, serialize_challenge, deserialize_challenge,
   serialize_response, and deserialize_response call into the scalar
   serialize and deserialize functions.  Likewise, serialize_commitment
   and deserialize_commitment call into the group element serialize and
   deserialize functions.

6.1.  NISigmaProtocol instances (ciphersuites)

   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.

   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

7.  Codec for Schnorr proofs

   We describe a codec for Schnorr proofs over groups of prime order p
   where Unit = u8.








Orrù                    Expires 3 September 2026                [Page 8]

Internet-Draft         Fiat-Shamir Transformation             March 2026


   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

   We describe a codec for the P256 curve.

   class P256Codec(ByteSchnorrCodec):
       GG = groups.GroupP256()

8.  Duplex Sponge Interfaces

8.1.  SHAKE128

   SHAKE128 is a variable-length extendable-output function based on the
   Keccak sponge construction [SHA3].  It belongs to the SHA-3 family
   and is used here to provide a duplex sponge interface.

8.1.1.  Initialization

  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)

8.1.2.  SHAKE128 Absorb






Orrù                    Expires 3 September 2026                [Page 9]

Internet-Draft         Fiat-Shamir Transformation             March 2026


   absorb(state, x)

   Inputs:

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

   1. h.update(x)

8.1.3.  SHAKE128 Squeeze

   squeeze(state, length)

   Inputs:

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

   1. return self.state.copy().digest(length)

8.2.  Duplex Sponge

   A duplex sponge in overwrite mode is based on a permutation function
   that operates on a state vector.  It implements the
   DuplexSpongeInterface and maintains internal state to support
   incremental absorption and variable-length output generation.

8.2.1.  Initialization

   This is the constructor for a duplex sponge object.  It is
   initialized with a 64-byte initialization vector.

  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

8.2.2.  Absorb

   The absorb function incorporates data into the duplex sponge state
   using overwrite mode.




Orrù                    Expires 3 September 2026               [Page 10]

Internet-Draft         Fiat-Shamir Transformation             March 2026


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:]

8.2.3.  Squeeze

   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.

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






Orrù                    Expires 3 September 2026               [Page 11]

Internet-Draft         Fiat-Shamir Transformation             March 2026


8.2.4.  Keccak-f[1600] Implementation

   Keccak-f is the permutation function underlying [SHA3].

   KeccakDuplexSponge instantiates DuplexSponge with Keccak-f[1600],
   using rate R = 136 bytes and capacity C = 64 bytes.

9.  Codecs registry

9.1.  Elliptic curves

9.1.1.  Notation and Terminology

   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.

   The following functions and notation are used throughout the
   document.

*  concat(x0, ..., xN): Concatenation of byte strings.

*  OS2IP and I2OSP: Convert a byte string to and from a non-negative
   integer, as described in [RFC8017].  Note that these functions
   operate on byte strings in big-endian byte order.

*  The function ecpoint_to_bytes converts an elliptic curve point in
   affine-form into an array string of length
   ceil(ceil(log2(coordinate_field_order))/ 8) + 1 using int_to_bytes
   prepended by one byte.  This is defined as

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)





Orrù                    Expires 3 September 2026               [Page 12]

Internet-Draft         Fiat-Shamir Transformation             March 2026


9.1.2.  Absorb scalars

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))

9.1.3.  Absorb elements

   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))

9.1.4.  Decoding random bytes as scalars

   Given Ns + 16 bytes, it is possible to generate a scalar modulo p
   that is statistically close to uniform.  Interpret the bytes as a
   big-endian integer, then reduce it modulo p, where p is the order of
   the group.

















Orrù                    Expires 3 September 2026               [Page 13]

Internet-Draft         Fiat-Shamir Transformation             March 2026


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)

10.  References

10.1.  Normative References

   [RFC8017]  Moriarty, K., Ed., Kaliski, B., Jonsson, J., and A. Rusch,
              "PKCS #1: RSA Cryptography Specifications Version 2.2",
              RFC 8017, DOI 10.17487/RFC8017, November 2016,
              <https://www.rfc-editor.org/rfc/rfc8017>.

   [SIGMA]    Orrù, M. and C. Yun, "Interactive Sigma Proofs", Work in
              Progress, Internet-Draft, draft-irtf-cfrg-sigma-protocols-
              00, 8 August 2025, <https://datatracker.ietf.org/doc/html/
              draft-irtf-cfrg-sigma-protocols-00>.

10.2.  Informative References

   [SHA3]     "SHA-3 Standard: Permutation-Based Hash and Extendable-
              Output Functions", n.d.,
              <https://nvlpubs.nist.gov/nistpubs/FIPS/
              NIST.FIPS.202.pdf>.

Appendix A.  Test Vectors

A.1.  test_keccak_duplex_sponge_SHAKE128

   DuplexSponge = SHAKE128
   IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:6261736963206475706c65782073706f6e67652074657374
   Operation2 = squeeze:64
   Expected = f845c3ef4231a4d6e09c29b1eea0055842246fd57558fd7d93e1302f7
   799dd9593d2e4d06eda72d5252ca5b2feff4b8cb324ec96673a7417cf70fa77b1898
   991



Orrù                    Expires 3 September 2026               [Page 14]

Internet-Draft         Fiat-Shamir Transformation             March 2026


A.2.  test_absorb_empty_before_does_not_break_SHAKE128

   DuplexSponge = SHAKE128
   IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:656d707479206d657373616765206166746572
   Operation2 = absorb:
   Operation3 = squeeze:64
   Expected = 3953e577d9e5d4dc7b86d1a62e881f2d1eb750ea3550fcae315854d16
   6136ae816ca922a4c7e54d711b8721c8969598449922122768c50313f47eef35020b
   73c

A.3.  test_absorb_empty_after_does_not_break_SHAKE128

   DuplexSponge = SHAKE128
   IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:
   Operation2 = absorb:656d707479206d657373616765206265666f7265
   Operation3 = squeeze:64
   Expected = 6e475edd3c400bec314d5891af570841a547c95d1a651adff9a8bfb70
   719a79b5afde316386da13fa83525662df3c5b2367d987bf3dc4199efdb9d0612572
   785

A.4.  test_squeeze_zero_behavior_SHAKE128

   DuplexSponge = SHAKE128
   IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = squeeze:0
   Operation2 = absorb:7a65726f2073717565657a652074657374
   Operation3 = squeeze:0
   Operation4 = squeeze:64
   Expected = 4cf7f008057b63cb615547a143f42cf793b86b239f404d2f28b3f0919
   7d850eb029df3024ad468be5aceb2fa60e9fb7add98436236be69ddb34314ce7a905
   f23

A.5.  test_squeeze_zero_after_behavior_SHAKE128

   DuplexSponge = SHAKE128
   IV = 756e69745f74657374735f6b656363616b5f697600000000000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = squeeze:0
   Operation2 = absorb:7a65726f2073717565657a65206166746572
   Operation3 = squeeze:64
   Expected = bd9278e6f65cb854935b3f6b2c51ab158be8ea09744509519b8f06f0c
   501d07c429e37f232b6f0955b620ff6226d9d02e4817b1447e7309023a3a14f73587
   6ec



Orrù                    Expires 3 September 2026               [Page 15]

Internet-Draft         Fiat-Shamir Transformation             March 2026


A.6.  test_absorb_squeeze_absorb_consistency_SHAKE128

   DuplexSponge = SHAKE128
   IV = 656467652d636173652d746573742d646f6d61696e2d6162736f72620000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:696e7465726c65617665206669727374
   Operation2 = squeeze:32
   Operation3 = absorb:696e7465726c65617665207365636f6e64
   Operation4 = squeeze:32
   Expected = 4d31a75f29851f9f15cd54fa6f2335cbe07b947b9d3c28092c1ba7315
   e295921

A.7.  test_associativity_of_absorb_SHAKE128

   DuplexSponge = SHAKE128
   IV = 6162736f72622d6173736f6369617469766974792d646f6d61696e000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:6173736f63696174697669747920746573742066756c6c
   Operation2 = squeeze:32
   Expected = c0faa351141d60678dceff4f3a5760381bb335ad113958b70edf7b242
   df01c8a

A.8.  test_iv_affects_output_SHAKE128

   DuplexSponge = SHAKE128
   IV = 646f6d61696e2d6f6e652d646966666572732d6865726500000000000000000
   00000000000000000000000000000000000000000000000000000000000000000
   Operation1 = absorb:697620646966666572656e63652074657374
   Operation2 = squeeze:32
   Expected = 7650642267cc544abf0e01ce28e2595aec4c2f5b5e5e3720ab5514496
   37b35f2

A.9.  test_multiple_blocks_absorb_squeeze_SHAKE128


















Orrù                    Expires 3 September 2026               [Page 16]

Internet-Draft         Fiat-Shamir Transformation             March 2026


   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

Author's Address

   Michele Orrù
   CNRS
   Email: m@orru.net





Orrù                    Expires 3 September 2026               [Page 17]
