Poseidon

General Notation

Types

x:T
A variable
x
having type
T
.

v:T[n]
An array of
n
elements each of type
T
.

A:T[n×n]
An
n×n
matrix having elements of type
T
.

In:T[n×n]
The
n×n
identity matrix.

v:T[n×n][m]
An array of
m
matrices.

b:{0,1}
A bit
b
.

bits:{0,1}[n]
An array
bits
of
n
bits.

x:Zp
A prime field element
x
.

xZn
An integer in
x[0,n)
.

x:Z0
A non-negative integer.

x:Z>0
A positive integer.

[n]
The range of integers
0,,n1
. Note that
[n]=[0,n)
.

[a,b)
The range of integers
a,,b1
.

Array Operations

Note: all arrays and matrices are indexed starting at zero. An array of

n elements has indices
0,,n1
.

v[i]
Returns the
ith
element of array
v
. When the notation
v[i]
is cumbersome
vi
is used instead.

v[i..j]
Returns a slice of the array
v
:
[v[i],,v[j1]]
.

vw
Concatenates two arrays
v
and
w
, of types
T[m]
and
T[n]
respectively, producing an array of type
T[m+n]
. The above is equivalent to writing
[v0,,vm1,w0,,wn1]
.

[f()]i{1,2,3}
Creates an array using list comprehension; each element of the array is the output of the expression
f()
at each element of the input sequence (e.g.
i{1,2,3}
).

vw
Element-wise field addition of two equally lengthed vectors of field elements
v,w:Zp[n]
. The above is equivalent to writing
[v0w0,,vn1wn1]
.

reverse(v)
Reverses the elements of a vector
v
, i.e. the first element of
reverse(v)
is the last element of
v
.

Matrix Operations

Ai,j
Returns the value of matrix
A
at row
i
column
j
.

Ai,
Returns the
ith
row of matrix
A
.

A,j
Returns the
jth
column of matrix
A
.


A1..,1..=[A1,1A1,c1Ar1,1Ar1,c1]
Returns a submatrix of
m
which excludes
m
's first row and first column (here
m
is an
r×c
matrix).

A×B
Matrix-matrix multiplication of two matrices of field elements
A:Zpm×n
and
B:Zpn×k
which produces a matrix of type
Zp[m×k]
. Note that
(A×B)i,j=Ai,\boldsymbolB,j
where the dot product uses field multiplication.

A-1
The inverse of a square
n×n
matrix, i.e. returns the matrix such that
A×A-1=In
.


v×A=[v0,,vm1][A0,0A0,n1Am1,0Am1,n1]=[v\boldsymbolA,i]i[n]
Vector-matrix multiplication of a row vector of field elements
v:Zp[m]
with a matrix of field elements
m:Zp[m×n]
, note that
len(v)=rows(A)
and
len(v×A)=columns(A)
. The product is a row vector of length
n
(the number of matrix columns). The
ith
element of the product vector is the dot product of
v
and the
ith
column of
A
. Note that dot products use field multiplication.


A×v=[A0,0A0,n1Am1,0Am1,n1][v0vn1]=[A0,\boldsymbolvAm1,\boldsymbolv]
Matrix-vector multiplication of a volumn vector
v:T[m×1]
and matrix
A:T[m×n]
, note that
rows(v)=columns(A)
and
rows(A×v)=rows(A)
. The product is a column vector whose length is equal to the number of rows of
A
. The
ith
element of the product vector is the dot product of the
ith
row of
A
with
v
. Note that dot products use field multiplication.

Note:

v×A=(A×v)T when
A
is symmetric
A=AT
(the
ith
row of
A
equals the
ith
column of
A
), i.e. the row vector-matrix product and matrix-column vector product contain the same elements when
A
is symmetric.

Field Arithmetic

ab
Addition in
Zp
of two field elements
a
and
b
.

xα
Exponentiation in
Zp
of a field element
x
to an integer power
α
.

Bitwise Operations

xor
Bitwise XOR.

xor i{1,2,3}i
XOR's all values of a sequence. The above is equivalent to writing
1xor2xor3
.

Bitstrings

[1,0,0]=1002
A bit array can be written as an array
[1,0,0]
or as a bitstring
1002
. The leftmost bit of the bitstring corresponds to the first bit in the array.

Binary-Integer Conversions

Note: the leftmost digit of an integer

x:Zp0 is the most significant, thus a right-shift by
n
bits is defined:
xn=x/2n
.

x as {0,1}msb[n]
Converts an integer
x:Z0
into its
n
-bit binary representation. The most-significant bit (
msb
) is first (leftmost) in the produced bit array
{0,1}[n]
. The above is equivalent to writing
reverse([(xi)1]i[log2(x)])
. For example,
6 as {0,1}msb[3]=[1,1,0]
.

bitsmsb as Z0
Converts a bit array
bits:{0,1}[n]
into a unsigned (non-negative) integer where the first bit in
bits
is the most significant (
msb
). The above is equivalent to writing
i[n]2ireverse(bits)[i]
.

Poseidon-Specific Symbols

p:Z>0
The prime field modulus.

M{80,128,256}
The security level measured in bits. Poseidon allows for 80, 128, and 256-bit security levels.

t:Z>0=len(preimage)+len(digest)=len(preimage)+2Mlog2(p)
The width of a Poseidon instance; the length in field elements of an instance's internal
state
array. The width
t
is equal to the preimage length plus the output length, where output length is equal to the number of field elements
2Mlog2(p)
required to achieve the targeted security level
M
in a field of size
log2(p)
. Stated another way, each field element in a Poseidon digest provides and additional
log2(p)2
bits of security.

(p,M,t)
A Poseidon instance. Each instance is fully specified using this parameter triple.

α{-1,3,5}
The S-box function's exponent
S(x)=xα
, where
gcd(α,p1)=1
. Poseidon allows for exponents -1, 3, and 5.

RF:Z>0
The number of full rounds.
RF
is even.

RP:Z>0
The number of partial rounds.

R=RF+RP
The total number of rounds

Rf=RF/2
Half the number of full rounds.

r[R]
The index of a round.

r[Rf]
The round index for a first-half full round.

r[Rf+RP,R)
The round index for a second-half full round.

r[Rf,Rf+RP)
The round index for a partial round.

state:Zp[t]
A Poseidon instance's internal state array of
t
field elements which are transformed in each round.

RoundConstants:Zp[Rt]
The round constants for an unoptimized Poseidon instance.

RoundConstantsr:Zp[t]
The round constants for round
r[R]
for an unoptimized Poseidon instance, that are added to
state
before round
r
's S-boxes.

RoundConstants:Zp[tRF+RP]=RoundConstantspreRoundConstants1RoundConstantsR2
The round constants for an optimized Poseidon instance. There are no constants associated with the last full round
r=R1
.

RoundConstantspre:Zp[t]
The round constants that are added to Poseidon's
state
array before the S-boxes in the first round
r=0
of an optimized Poseidon instance.

RoundConstantsr:{Zp[1]if r[Rf,Rf+RP)i.e. r is a partial round Zp[t]if r[Rf] or r[Rf+RP,R1)i.e. r is a full round, excluding the last round
The round constants that are added to Poseidon's
state
array after the S-boxes in round
r
in an optimized Poseidon instance. Partial rounds have a single round constant, full rounds (excluding the last) have
t
constants. The last full round has no round constants.

M:Zp[t×t]
The MDS matrix for a Poseidon instance.

P:Zp[t×t]
The pre-sparse matrix used in MDS mixing for the last first-half full round (
r=Rf1
) of an optimized Poseidon instance.

S:Zp[t×t][RP]
An array of sparse matrices used in MDS mixing for the partial rounds
r[Rf,Rf+RP)
of the optimized Poseidon algorithm.

Poseidon Instantiation

The parameter triple

(p,M,t) fully specifies a unique instance of Poseidon (a hash function that uses the same constants and parameters and performs the same operations). All other Poseidon parameters and constants are derived from the instantiation parameters.

The S-box exponent

α is derived from the field modulus
p
such that
a{3,5}
and
gcd(α,p1)=1
.

The round numbers

RF and
RP
are derived from the field size and security level
(log2(p),M)
.

The

RoundConstants are derived from
(p,M,t)
.

The MDS matrix

M is derived from the width
t
.

The allowed preimage sizes are

len(preimage)[1,t).

The total number of operations executed per hash is determined by the width and number of rounds

(t,RF,RP).

Filecoin's Poseidon Instances

Note: the following are the Poseidon instantiation parameters used within Filecoin and do not represent all possible Poseidon instances.


p=52435875175126190479447740508185965837690552500527637822603658699938581184513
p=0x73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001

The Poseidon prime field modulus in base-10 and base-16. Filecoin uses BLS12-381's scalar field as the Poseidon prime field
Zp
, i.e.
p
is the order of BLS12-381's prime order subgroup
G1
. The bit-length of
p
is
log2(p)=255256
bits.


M=128 Bits
Filecoin targets the 128-bit security level.


t{3,5,9,12}={arity+1arity{2,4,8,11}}
The size in field elements of Poseidon's internal state; equal to the preimage length (a Filecoin Merkle tree arity) plus 1 for the digest length (the number of field elements required to target the
M=128
-bit security level via a 256-bit prime
p
). Filecoin's Poseidon instances take preimages of varying lengths (2, 4, 8, and 11 field elements) and always return one field element.

  • t=3
    is used to hash 2:1 Merkle trees (BinTrees) and to derive SDR-PoRep's
    CommR
  • t=5
    is used to hash 4:1 Merkle trees (QuadTrees)
  • t=9
    is used to hash 8:1 Merkle trees (OctTrees)
  • t=12
    is used to hash SDR-PoRep columns of 11 field elements.

α=5
The S-box function's
S(x)=xα
exponent. It is required that
α
is relatively prime to
p
, which is true for Filecoin's choice of
p
.

Round Numbers

The Poseidon round numbers are the number of full and partial rounds

(RF,RP) for a Poseidon instance
(p,M,t)
. The round numbers are chosen such that they minimize the total number of S-boxes:
Number of S-boxes=tRF+RP
while providing security against known attacks (statistical, interpolation, and Gröbner basis).


const RF,RP=calc_round_numbers(p,M,t,α)
The number of full and partial rounds, both are positive integers
RF,RP:Z>0
and
RF
is even.

RF and
RP
are calculated using either the Python script calc_round_numbers.py or the neptune Rust library, denoted
calc_round_numbers
. Both methods calculate the round numbers via brute-force; by iterating over all reasonable values for
RF
and
RP
and choosing the pair that satisfies the security inequalities (provided below) while minimizing the number of S-boxes.

Security Inequalities

The round numbers

RF and
RP
are chosen such that they satisfy the following inequalities. The symbol
is used to indicate that an inequality simplifies when Filecoin's Poseidon parameters
M=128
and
α=5
are plugged in.

(1)2Mpt
Equivalent to writing
Mtlog2(p)
(Appendix C.1.1 in the Poseidon paper). This is always satisfied for Filecoin's choice of
p
and
M
.

(2)Rf6
The minimum
RF
necessary to prevent statistical attacks (Eq. 2 Section 5.5.1 in the Poseidon paper where
log2(p)2=252
and
C=2
for
α=5
).

(3)R>Mlogα(2)+logα(t)    R>{57if t[2,5]58if t[6,25]
The minimum number of total rounds necessary to prevent interpolation attacks (Eq. 3 Section 5.5.2 of the Poseidon paper).

(4a)R>Mlogα(2)3    R>18.3
(4b)R>t1+Mlogα(2)t+1

The minimum number of total rounds required to prevent against Gaussian elimination attacks (both equations must be satisfied, Eq. 5 from Section 5.5.2 of the Poseidon paper).

Round Constants

Note: this section gives the round constants for only the unoptimized Poseidon algorithm.

Round Constants

const RoundConstants:Zp[Rt]
For each Poseidon instance
(p,M,t)
an array
RoundConstants
containing
Rt
field elements is generated (
t
field elements per round
r[R]
) using the Grain-LFSR stream cipher whose 80-bit state is initialized to
GrainStateinit
, an encoding of the Poseidon instance.

const RoundConstantsr:Zp[t]=RoundConstants[rt..(r+1)t]
The round constants for round
r[R]
for an unoptimized Poseidon instance.

const FieldBits:{0,1}msb[2]={0if using a binary field Z2m1if using a prime field Zp=012
Specifies the field type as prime or binary. Filecoin always uses a prime field
Zp
, however Poseidon also can be instantiated using a binary field
Z2m
.

const SboxBits:{0,1}msb[4]={0if α=31if α=52if α=-1=00012
Specifies the S-box exponent
α
. Filecoin uses
α=5
.

const FieldSizeBits:{0,1}msb[12]=log2(p)=255=0000111111112
The bit-length of the field modulus.

const GrainStateinit:{0,1}[80]=
FieldBits

 SboxBits

 FieldSizeBits

 t as {0,1}msb[12]

 RF as {0,1}msb[10]

 RP as {0,1}msb[10]

 1[30]

Initializes the Grain-LFSR stream cipher which is used to derive
RoundConstants
for a Poseidon instance
(p,M,t)
.

Algorithm: RoundConstants
1.10.  state:{0,1}[80]=GrainStateinit

2.10.  do 160 times:

3.10.  bit:{0,1}=xor i{0,13,23,38,51,62}state[i]

4.10.  state=state[1..]bit

5.10.  RoundConstants:Zp[Rt]=[ ]

6.10.  while len(RoundConstants)<Rt:

7.10.  bits:{0,1}[255]=[ ]

8.10.  while len(bits)<255:

9.10.  bit1=xor i{0,13,23,38,51,62}state[i]

10.10.  state=state[1..]bit1

11.10.  bit2=xor i{0,13,23,38,51,62}state[i]

12.10.  state=state[1..]bit2

13.10.  if bit1=1:

14.10.  bits.push(bit2)

15.10.  c=bitsmsb as Z2255

16.10.  if cZp:

17.10.  RoundConstants.push(c)

18.10.  return RoundConstants

MDS Matrix

const x:Zp[t]=[0,,t1]
const y:Zp[t]=[t,,2t1]

const M:Zp[t×t]=[(x0+y0)-1(x0+yt1)-1(xt1+y0)-1(xt1+yt1)-1]

The MDS matrix

M for a Poseidon instance of width
t
. The superscript
-1
denotes a multiplicative inverse
mod p
. The MDS matrix is invertible and symmetric.

Domain Separation

Every preimage hashed is associated with a hash type

HashType to encode the Poseidon application, note that
HashType
is specified per preimage and does not specify a Poseidon instance.

Filecoin uses two hash types

MerkleTree and
ConstInputLen
to designate a preimage as being for a Merkle tree of arity
t1
or being for no specific application, but having a length
len(preimage)<t
.

The

HashType determines the
DomainTag
and
Padding
used for a preimage, which give the first element of Poseidon's initial state:
state=DomainTagpreimagePadding.


const HashType{MerkleTree,ConstInputLen}
The allowed hash types in which to hash a preimage for a Poseidon instance
(p,M,t)
. It is required that
1len(preimage)<t
.

  • A
    HashType
    of
    MerkleTree
    designates a preimage as being the preimage of a Merkle tree hash function, where the tree is
    (t1):1
    (i.e.
    arity=len(preimage)
    number of nodes are hashed into
    1
    node).
  • A
    HashType
    of
    ConstInputLen
    designates Poseidon as being used to hash preimages of length exactly
    len(preimage)
    into a single output element (where
    1len(preimage)<t
    ).

const DomainTag:Zp={2arity1if HashType=MerkleTree264len(preimage)if HashType=ConstInputLen
Encodes the Poseidon application within the first Poseidon initial state element
state[0]
for a preimage.


const Padding:Zp[]={[ ]if HashType=MerkleTree0[t1len(preimage)]if HashType=ConstInputLen
The padding that is applied to Poseidon's initial state. A
HashType
of
MerkleTree
results in no applied padding; a
HashType
of
ConstInputLen
pads the last
t1len(preimage)
elements of Poseidon's initial
state
to zero.

Poseidon Hash Function

The Posiedon hash function takes a preimage of

t1 prime field
Zp
elements to a single field element. Poseidon operates on an internal state
state
of
t
field elements which, in the unoptimized algorithm, are transformed over
R
number of rounds of: round constant addition, S-boxes, and MDS matrix mixing. Once all rounds have been performed, Poseidon outputs the second element of the state.

A Posiedon hash function is instantiated by a parameter triple

(p,M,t) which sets the prime field, the security level, and the size of Poseidon's internal state buffer
state
. From
(p,M,t)
the remaining Poseidon parameters are computed
(α,RF,RP,RoundConstants,M)
, i.e. the S-box exponent, the round numbers, the round constants, and the MDS matrix.

The S-box function is defined as:

S:ZpZpS(x)=xα

The

state is initialized to the concatenation of the
DomainTag
,
preimage
, and
Padding
:

state=DomainTagpreimagePadding

Every round

r[R] begins with
t
field additions of the
state
with that round's constants
RoundConstantsr
:

state=stateRoundConstantsr.

If

r is a full round, i.e.
r<Rf
or
rRf+RP
, the S-box function is applied to each element of
state
:

state=[state[i]α]i[t]

otherwise, if

r is a partial round
r[Rf,Rf+RP)
, the S-box function is applied to the first
state
element exclusively:

state[0]=state[0]α.

Once the S-boxes have been applied for a round, the

state is transformed via vector-matrix multiplication with the MDS matrix
M
:

state=state×M.

After

R rounds of the above procedure, Poseidon outputs the digest
state[1]
.

Function: poseidon(preimage:Zp[t1])Zp
1.10.  state:Zp[t]=DomainTagpreimagePadding

2.10.  for r[R]:

3.10.  state=stateRoundConstantsr

4.10.  if r[Rf] or r[Rf+RP,R):

5.10.  state=[state[i]α]i[t]

6.10.  else

7.10.  state[0]=state[0]α

8.10.  state=state×M

9.10.  return state[1]

Poseidon algorithm

Optimizations

Filecoin's rust library neptune implements the Poseidon hash function. The library differentiates between unoptimized and optimized Poseidon using the terms correct and static respectively.

The primary differences between the two versions are:

  • the unoptimized algorithm uses the round constants
    RoundConstants
    , performs round constant addition before S-boxes, and uses the MDS matrix
    M
    for mixing
  • the optimized algorithm uses the transformed rounds constants
    RoundConstants
    (containing fewer constants than
    RoundConstants
    ), performs a round constant addition before the first round's S-box, performs round constant addition after every S-box other than the last round's, and uses multiple matrices for MDS mixing
    M
    ,
    P
    , and
    S
    . This change in MDS mixing from a non-sparse matrix
    M
    to sparse matrices
    S
    greatly reduces the number of multiplications in each round.

For a given Poseidon instance

(p,M,t) the optimized and unoptimized algorithms will produce the same output when provided with the same input.

Optimized Round Constants

Given the round constants

RoundConstants and MDS matrix
M
for a Poseidon instance, we are able to derive round constants
RoundConstants
for the corresponding optimized Poseidon instance.

Optimized round constants

const RoundConstants:Zp[tRF+RP]
The round constants for a Poseidon instance's
(p,M,t)
optimized hashing algorithm. Each full round is associated with
t
round constants, while each partial round is associated with one constant.

Algorithm: RoundConstants
1.10.  RoundConstants:Zp[tRF+RP]=[ ]

2.10.  RoundConstants.extend(RoundConstants0)

3.10.  for r[1,Rf):

4.10.  RoundConstants.extend(RoundConstantsr×M-1)

5.10.  partial_consts:Zp[RP]=[ ]

6.10.  acc:Zp[t]=RoundConstantsRf+RP

7.10.  for rreverse([Rf,Rf+RP)):

8.10.  acc=acc×M-1

9.10.  partial_consts.push(acc[0])

10.10.  acc[0]=0

11.10.  acc=accRoundConstantsr

12.10.  RoundConstants.extend(acc×M-1)

13.10.  RoundConstants.extend(reverse(partial_consts))

14.10.  for r[Rf+RP+1,R)

15.10.  RoundConstants.extend(RoundConstantsr×M-1)

16.10.  return RoundConstants

Algorithm Comments:
Note:

× denotes a row vector-matrix multiplication which outputs a row vector.
Line 2. The first
t
round constants are unchanged. Note that both
RoundConstants0
and
RoundConstants1
are used in the first optimized round
r=0
.
Lines 3-4. For each first-half full round, transform the round constants into
RoundConstantsr×M-1
.
Line 5. Create a variable to store the round constants for the partial rounds
partial_consts
(in reverse order).
Line 6. Create and initialize a variable
acc
that is transformed and added to
RoundConstantsr
in each
do
loop iteration.
Lines 7-11. For each partial round
r
(starting from the greatest partial round index
Rf+RP1
and proceeding to the least
Rf
) transform
acc
into
acc×M-1
, take its first element as a partial round constant, then perform element-wise addition with
RoundConstantsr
. The value of
acc
at the end of the
ith
loop iteration is:
acci=RoundConstantsr[0]((acci1×M-1)[1..]RoundConstantsr[1..])
Line 12. Set the last first-half full round's constants using the final value of
acc
.
Line 13. Set the partial round constants.
Lines 14-15. Set the remaining full round constants.


const RoundConstantspre:Zp[t]=RoundConstants[..t]
The first
t
constants in
RoundConstants
are added to
state
prior to applying the S-box in the first round round
r=0
.


const RoundConstantsr:Zp[]={RoundConstants[(r+1)t..(r+2)t]if r[Rf]RoundConstants[(Rf+1)t+rP]if r[Rf,Rf+RP)where rP=rRf is the partial round index rP[RP]RoundConstants[(rF+1)t+RP..(rF+2)t+RP]if r[Rf+RP,R1)where rF=rRP is the full round index rF[RF1] (excludes the last full round)
For each round excluding the last
r[R1]
,
RoundConstantsr
is added to the Poseidon
state
after that round's S-box has been applied.

Sparse MDS Matrices

A sparse matrix

A is a square
n×n
matrix whose first row and first column are utilized and where all other entries are the
n1×n1
identity matrix
In1
:

A=[A0,0A0,1..A1..,0In1]=[A0,0A0,n110An1,001]

The MDS matrix

M is factored into a non-sparse matrix
P
and an array of sparse matrices
S=[S0,,SRP1]
(one matrix per partial round).
P
is used in MDS mixing for the last first-half full round
r=Rf1
. Each matrix of
S
is used in MDS mixing for a partial round. The first sparse matrix
S0
is used in the first partial round (
r=Rf
) and the last sparse matrix
SRP1
is used in the last partial round (
r=Rf+i
).

const P:Zp[t×t]
The pre-sparse matrix (a non-sparse matrix) used in MDS mixing for the last full round of the first-half
r=Rf1
. Like the MDS matrix
M
, the pre-sparse matrix
P
is symmetric.

const S:Zp[t×t][RP]
The array of sparse matrices that
M
is factored into, which are used for MDS mixing in the optimized partial rounds.

Algorithm: P,S
1.10.  sparse:Zp[t×t][RP]=[ ]

2.10.  m:Zp[t×t]=M

3.10.  do RP times:

4.10.  (m,m):(Zp[t×t],Zp[t×t])=sparse_factorize(m)

5.10.  sparse.push(m)

6.10.  m=M×m

7.10.  P=m

8.10.  S=reverse(sparse)

9.10.  return P,S

Algorithm Comments:
Line 1. An array containing the sparse matrices that

M is factored into.
Line 2. A matrix
m
that is repeatedly factored into a non-sparse matrix
m
and a sparse matrix
m
, i.e.
m=m×m
.
Lines 3-6. In each loop iteration we factor
m
into
m
and
m
. The first
do
loop iteration calculates the sparse matrix
m
used in MDS mixing for last partial round
r=Rf+RP1
. The last
do
loop iteration calculates the sparse matrix
m
used in MDS mixing for the first partial round
r=Rf
(i.e.
S0=m
).
Line 6.
M×m
is a matrix-matrix multiplication which produces a
t×t
matrix.


The function

sparse_factorize factors a non-sparse matrix
m
into a non-sparse matrix
m
and sparse matrix
m
such that
m=m×m
.

Function: sparse_factorize(m:Zp[t×t])(m:Zp[t×t],m:Zp[t×t])
1.10.  m^:Zp[t1×t1]=m1..,1..=[m1,1m1,t1mt1,1mt1,t1]

2.10.  m:Zp[t×t]=[100m^]=[1000m1,1m1,t10mt1,1mt1,t1]

3.10.  w:Zp[t1×1]=m1..,0=[m^1,0m^t1,0]

4.10.  w^:Zp[t1×1]=m^-1×w=[m^-10,\boldsymbolwm^-1t2,\boldsymbolw]

5.10.  m:Zp[t×t]=[m0,0m0,1..w^It1]=[m0,0m0,t1w^010w^t201]
6.10.  return m,m

Algorithm Comments:
Line 1.

m^ is a submatrix of
m
which excludes
m
's first row and first column.
Line 2.
m
is a copy of
m
where
m
's first row and first column have been replaced with
[1,0,,0]
.
Line 3.
w
is a column vector whose values are the first column of
m
excluding
m
's first row.
Line 4.
w^
is the matrix-column vector product of
m^-1
and
w
.
Line 5.
m
is a sparse matrix whose first row is the first row of
m
, remaining first column is
w^
, and remaining entries are the identity matrix.

Optimized Poseidon

The optimized Poseidon hash function is instantiated in the same way as the unoptimized algorithm, however the optimized Poseidon algorithm requires the additional precomputation of round constants

RoundConstants, a pre-sparse matrix
P
, and sparse matrices
S
.

Prior to the first round

r=0, the
state
is initialized and added to the pre-first round constants
RoundConstantspre
:

state=DomainTagpreimagePaddingstate=stateRoundConstantspre

For each full round of the first-half

r[Rf]: the S-box function is applied to each element of
state
, the output of each S-box is added to the associated round constant in
RoundConstantsr
, and MDS mixing occurs between
state
and the MDS matrix
M
(when
r<Rf1
) or the pre-sparse matrix
P
(when
r=Rf1
).

state={[state[i]αRoundConstantsr[i]]i[t]×Mif r[Rf1][state[i]αRoundConstantsr[i]]i[t]×Pif r=Rf1

For each partial round

r[Rf,Rf+RP) the S-box function is applied to the first
state
element, the round constant is added to the first
state
element, and MDS mixing occurs between the
state
and the
ith
sparse matrix
Si
(the
ith
partial round
i[RP]
is associated with sparse matrix
Si
where
i=rRf
):

state[0]=state[0]αRoundConstantsrstate=state×SrRf

The second half of full rounds

r[Rf+RP,R) proceed in the same way as the first half of full rounds except that all MDS mixing uses the MDS matrix
M
and that the last round
r=R1
does not add round constants into
state
.

After performing

R rounds, Poseidon outputs the digest
state[1]
.

Function: poseidon(preimage:Zp[t1])Zp
1.10.  state:Zp[t]=DomainTagpreimagePadding

2.10.  state=stateRoundConstantspre

3.10.  for r[Rf1]:

4.10.  state=[state[i]αRoundConstantsr[i]]i[t]×M

5.10.  state=[state[i]αRoundConstantsRf1[i]]i[t]×P

6.10.  for r[Rf,Rf+RP):

7.10.  state[0]=state[0]αRoundConstantsr

8.10.  state=state×SrRf

9.10.  for r[Rf+RP,R1):

10.10.  state=[state[i]αRoundConstantsr[i]]i[t]×M

11.10.  state=[state[i]α]i[t]×M

12.10.  return state[1]

Algorithm Comments:
Line 1. Initialize the

state.
Line 2. Adds the pre-
r=0
round constants.
Lines 3-4. Performs all but the last first-half of full rounds
r[Rf1]
.
Line 5. Performs the last first-half full round
r=Rf1
.
Lines 6-8. Performs the partial rounds
r[Rf,Rf+RP)
. Mixing in the
ith
partial round, where
i=rRf
, is done using the
ith
sparse matrix
SrRf
.
Lines 9-10. Performs all but the last second-half full rounds
r[Rf+RP,R1)
.
Line 11. Performs the last second-half rull round
r=R1
.

Optimized poseidon algorithm