Note: all arrays and matrices are indexed starting at zero. An array of n elements has indices $0, \dots, n - 1$.
v[i]
Returns the ith element of array v. When the notation v[i] is cumbersome vi is used instead.
v[i\dotdotj]
Returns a slice of the array v: [v[i],…,v[j−1]].
v∥w
Concatenates two arrays v and w, of types T[m] and T[n] respectively, producing an array of type T[m+n]\hso. The above is equivalent to writing [v0,…,vm−1,w0,…,wn−1].
[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}).
v⊕w
Element-wise field addition of two equally lengthed vectors of field elements v,w\typecolon\Zp[n]. The above is equivalent to writing [v0⊕w0,…,vn−1⊕wn−1].
\reverse(v)
Reverses the elements of a vector v, i.e. the first element of \reverse(v) is the last element of v.
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\dotdot,1\dotdot=A1,1⋮Ar−1,1…⋱…A1,c−1⋮Ar−1,c−1
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\typecolon\Zp[m×n] and B\typecolon\Zp[n×k] which produces a matrix of type \Zp[m×k]. Note that \AtimesBi,j=Ai,∗⋅B∗,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,…,vm−1]A0,0⋮Am−1,0…⋱…A0,n−1⋮Am−1,n−1=[v⋅A∗,i]i∈[n]
Vector-matrix multiplication of a row vector of field elements v\typecolon\Zp[m] with a matrix of field elements m\typecolon\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,0⋮Am−1,0…⋱…A0,n−1⋮Am−1,n−1v0⋮vn−1=A0,∗⋅v⋮Am−1,∗⋅v
Matrix-vector multiplication of a volume vector v\typecolonT[m×1] and matrix A\typecolonT[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.
[1,0,0]=1002
A bit array can be written as an array [1,0,0] or as a bitstring $100_2$. The leftmost bit of the bitstring corresponds to the first bit in the array.
Note: the leftmost digit of an integer x\typecolon\Zp≥0 is the most significant, thus a right-shift by n bits is defined: x≫n=x/2n.
x\as\Bit\msb[n]
Converts an integer x\typecolonZ≥0 into its n-bit binary representation. The most-significant bit (\msb) is first (leftmost) in the produced bit array \Bit[n]. The above is equivalent to writing \reverse([(x≫i)∧1]i∈[⌈log2(x)⌉]). For example, $6 \as \Bit_\msb^{[3]} = [1, 1, 0]$.
\bits\msb\asZ≥0
Converts a bit array \bits\typecolon\Bit[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]2i∗\reverse(\bits)[i].
M∈{80,128,256}
The security level measured in bits. Poseidon allows for 80, 128, and 256-bit security levels.
t\typecolonZ>0=\len(\preimage)+\len(digest)=\len(\preimage)+⌈log2(p)2M⌉
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 ⌈log2(p)2M⌉ 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 2log2(p) 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(α,p−1)=1. Poseidon allows for exponents -1, 3, and 5.
RF\typecolonZ>0
The number of full rounds. RF is even.
RP\typecolonZ>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\typecolon\Zp[t]
A Poseidon instance's internal state array of t field elements which are transformed in each round.
\RC\typecolon\Zp[Rt]
The round constants for an unoptimized Poseidon instance.
\RCr\typecolon\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.
\RC′\typecolon\Zp[tRF+RP]=\RCpre′∥\RC1′∥…∥\RCR−2′
The round constants for an optimized Poseidon instance. There are no constants associated with the last full round r=R−1.
\RCpre′\typecolon\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.
\RCr′\typecolon{\Zp[1]\Zp[t]\ifr∈[Rf,Rf+RP)\ifr∈[Rf] or r∈[Rf+RP,R−1)i.e. r is a partial round 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.
\Mds\typecolon\Zp[t×t]
The MDS matrix for a Poseidon instance.
\Pre\typecolon\Zp[t×t]
The pre-sparse matrix used in MDS mixing for the last first-half full round (r=Rf−1) of an optimized Poseidon instance.
\Sparse\typecolon\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.
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(α,p−1)=1.
The round numbers RF and RP are derived from the field size and security level (⌈log2(p)⌉,M).
The \RC are derived from (p,M,t).
The MDS matrix \Mds 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).
Note: the following are the Poseidon instantiation parameters used within Filecoin and do not represent all possible Poseidon instances.
p=52435875175126190479447740508185965837690552500527637822603658699938581184513p=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)⌉=255≈256 bits.
M=128Bits
Filecoin targets the 128-bit security level.
t∈{3,5,9,12}={arity+1∣arity∈{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.
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).
\constb R_F, R_P = \texttt{calc_round_numbers}(p, M, t, \alpha)
The number of full and partial rounds, both are positive integers RF,RP\typecolonZ>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 \texttt{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.
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)2M≤pt
Equivalent to writing M≤tlog2(p) (Appendix C.1.1 in the Poseidon paper). This is always satisfied for Filecoin's choice of p and M.
(2)Rf≥6
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>{5758\ift∈[2,5]\ift∈[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>3Mlogα(2)⟹R>18.3(4b)R>t−1+t+1Mlogα(2)
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).
Note: this section gives the round constants for only the unoptimized Poseidon algorithm.
\constb\RC\typecolon\Zp[Rt]
For each Poseidon instance (p,M,t) an array \RC 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 GrainState\init, an encoding of the Poseidon instance.
\constb\RCr\typecolon\Zp[t]=\RC[rt\dotdot(r+1)t]
The round constants for round r∈[R] for an unoptimized Poseidon instance.
\constb\FieldBits\typecolon\Bit\msb[2]={01if using a binary field \Zbinif 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 \Zbin.
\constb\SboxBits\typecolon\Bit\msb[4]=⎩⎨⎧012\ifα=3\ifα=5\ifα=¬1=00012
Specifies the S-box exponent α. Filecoin uses α=5.
\constbFieldSizeBits\typecolon\Bit\msb[12]=⌈log2(p)⌉=255=0000111111112
The bit-length of the field modulus.
\constbGrainStateinit\typecolon\Bit[80]=FieldBits∥\SboxBits∥FieldSizeBits∥t\as\Bit\msb[12]∥RF\as\Bit\msb[10]∥RP\as\Bit\msb[10]∥1[30]
Initializes the Grain-LFSR stream cipher which is used to derive \RC for a Poseidon instance (p,M,t).
\constb\xb\typecolon\Zp[t]=[0,…,t−1]\constb\yb\typecolon\Zp[t]=[t,…,2t−1]\constb\Mds\typecolon\Zp[t×t]=(\xb0+\yb0)¬1⋮(\xbt−1+\yb0)¬1…⋱…(\xb0+\ybt−1)¬1⋮(\xbt−1+\ybt−1)¬1
The MDS matrix \Mds for a Poseidon instance of width t. The superscript ¬1 denotes a multiplicative inverse mod p. The MDS matrix is invertible and symmetric.
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 t−1 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=\DomainTag∥\preimage∥\Padding.
\constb\HashType∈{\MerkleTree,\ConstInputLen}
The allowed hash types in which to hash a preimage for a Poseidon instance (p,M,t). It is required that $1 \leq \len(\preimage) < t \hso$.
A \HashType of \MerkleTree designates a preimage as being the preimage of a Merkle tree hash function, where the tree is (t−1)\hso:\hso1 (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 $1 \leq \len(\preimage) < t$).
Encodes the Poseidon application within the first Poseidon initial state element \state[0] for a preimage.
\constb\Padding\typecolon\Zp[∗]={[]0[t−1−\len(\preimage)]\if\HashType=\MerkleTree\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 t−1−\len(\preimage) elements of Poseidon's initial \state to zero.
The Posiedon hash function takes a preimage of t−1 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,\RC,\Mds), i.e. the S-box exponent, the round numbers, the round constants, and the MDS matrix.
The S-box function is defined as:
S:\Zp→\ZpS(x)=xα
The \state is initialized to the concatenation of the \DomainTag, \preimage, and \Padding:
\state=\DomainTag∥\preimage∥\Padding.
Every round r∈[R] begins with t field additions of the \state with that round's constants \RCr\hso:
\state=\state⊕\RoundConstantsr.
If r is a full round, i.e. r<Rf or r≥Rf+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:
\state=\state×\Mds.
After R rounds of the above procedure, Poseidon outputs the digest \state[1].
\Functionposeidon(\preimage\typecolon\Zp[t−1])→\Zp\line1\state\typecolon\Zp[t]=\DomainTag∥\preimage∥\Padding\line2\forr∈[R]\bcolon\line3\state=\state⊕\RCr\line4\ifbr∈[Rf] or r∈[Rf+RP,R)\bcolon\line5\state=[\state[i]α]i∈[t]\line6\else\line7\state[0]=\state[0]α\line8\state=\state×\Mds\line9\return\state[1]
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 \RC, performs round constant addition before S-boxes, and uses the MDS matrix \Mds for mixing
the optimized algorithm uses the transformed rounds constants \RC′ (containing fewer constants than \RC), 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 \Mds, \Pre, and \Sparse. This change in MDS mixing from a non-sparse matrix \Mds to sparse matrices \Sparse 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.
Given the round constants \RC and MDS matrix \Mds for a Poseidon instance, we are able to derive round constants \RC′ for the corresponding optimized Poseidon algorithm.
\constb\RC′\typecolon\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 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 \RC0′ and \RC1′ are used in the first optimized round r=0.
Lines 3-4. For each first-half full round, transform the round constants into \RCr\hso×\hso\MdsInv.
Line 5. Create a variable to store the round constants for the partial rounds \textsf{partial_consts} (in reverse order).
Line 6. Create and initialize a variable \acc that is transformed and added to \RCr in each do loop iteration.
Lines 7-11. For each partial round r (starting from the greatest partial round index Rf+RP−1 and proceeding to the least Rf) transform \acc into \acc\hso×\hso\MdsInv, take its first element as a partial round constant, then perform element-wise addition with \RCr. The value of \acc at the end of the ith loop iteration is:
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.
\constb\RCpre′\typecolon\Zp[t]=\RC′[\dotdott]
The first t constants in \RC′ are added to \state prior to applying the S-box in the first round round r=0.
\constb\RCr′\typecolon\Zp[∗]=⎩⎨⎧\RC′[(r+1)t\dotdot(r+2)t]\RC′[(Rf+1)t+rP]\RC′[(rF+1)t+RP\hso\dotdot\hso(rF+2)t+RP]\if\hsor∈[Rf]\ifr∈[Rf,Rf+RP),where rP=r−Rf is the partial round index rP∈[RP]\ifr∈[Rf+RP,R−1),where rF=r−RP is the full round index rF∈[RF−1] (excludes the last full round)
For each round excluding the last r∈[R−1], \RCr′ is added to the Poseidon \state after that round's S-box has been applied.
A sparse matrixm is a square n×n matrix whose first row and first column are utilized and where all other entries are the n−1×n−1 identity matrix In−1:
The MDS matrix \Mds is factored into a non-sparse matrix \Pre and an array of sparse matrices \Sparse=[\Sparse0,…,\SparseRP−1] (one matrix per partial round). \Pre is used in MDS mixing for the last first-half full round r=Rf−1. Each matrix of \Sparse is used in MDS mixing for a partial round. The first sparse matrix \Sparse0 is used in the first partial round (r=Rf) and the last sparse matrix \SparseRP−1 is used in the last partial round (r=Rf+i).
\constb\Pre\typecolon\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=Rf−1. Like the MDS matrix \Mds, the pre-sparse matrix \Pre is symmetric.
\constb\Sparse\typecolon\Zp[t×t][RP]
The array of sparse matrices that \Mds is factored into, which are used for MDS mixing in the optimized partial rounds.
Algorithm Comments:Line 1. An array containing the sparse matrices that \Mds is factored into.
Line 2. An array 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+RP−1. The last do loop iteration calculates the sparse matrix m′′ used in MDS mixing for the first partial round r=Rf (i.e. \Sparse0=m′′).
Line 6.\Mds×m′ is a matrix-matrix multiplication which produces a t×t matrix.
The function \textsf{sparse_factorize} factors a non-sparse matrix m into a non-sparse matrix m′ and sparse matrix m′′ such that m=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.\wb is a column vector whose values are the first column of m excluding m's first row.
Line 4.\wb^ is the matrix-column vector product of m^¬1 and \wb.
Line 5.m′′ is a sparse matrix whose first row is the first row of m, remaining first column is \wb^, and remaining entries are the identity matrix.
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 \RC′, a pre-sparse matrix \Pre, and sparse matrices \Sparse.
Prior to the first round r=0, the \state is initialized and added to the pre-first round constants \RCpre′:
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 \RCr′, and MDS mixing occurs between \state and the MDS matrix \Mds (when r<Rf−1) or the pre-sparse matrix \Pre (when r=Rf−1).
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 \Sparsei (the ith partial round i∈[RP] is associated with sparse matrix \Sparsei where i=r−Rf):
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 \Mds and that the last round r=R−1 does not add round constants into \state.
After performing R rounds, Poseidon outputs the digest \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∈[Rf−1].
Line 5. Performs the last first-half full round r=Rf−1.
Lines 6-8. Performs the partial rounds r∈[Rf,Rf+RP). Mixing in the ith partial round, where i=r−Rf, is done using the ith sparse matrix \Sparser−Rf.
Lines 9-10. Performs all but the last second-half full rounds r∈[Rf+RP,R−1).
Line 11. Performs the last second-half rull round r=R−1.