Block ciphers have been widely used in cryptography for many years. The idea is to separate a plaintext into fixed-sized blocks and perform transformations on these blocks in order to obtain a ciphertext. Block ciphers are also used in the construction of compression functions for the design of hash functions.
More recently, a new design paradigm for hash functions has been discovered a so-called sponge construction [2]. The cryptographic funtion keccak
, which is widely used in the Ethereum protocol, was the first implementation of sponge constructions [3].
The goal of this article is to introduce a general algorithm for sponge constructions without presenting any practical use. The main focus will be in giving a presentation of the algorithm for any fixed-length function with some accompanying code snippets. The idea behind this approach is to present some concrete realizations of all parts of the sponge construction. Security will not be discussed here. For more details the reader is encouraged to refer to the original references at the end of this article. The code snippets that will appear will be written in Python for the sake of claritiy.
The figure below (taken from https://keccak.team/sponge_duplex.html) presents a general view of the sponge construction.
Let us start explaining each part of this figure. Here
A sponge function is divided in two stages: (1) absorbing and (2) squeezing.
The idea for the absorbing stage is to divide
#M is a string a bits and r is a positive integer
def pad(M,r):
if len(M)%r != 0:
paddingBits = len(M)//r*r+r-len(M)
if paddingBits >= 2:
return M + "1" + "0"*(paddingBits-2) + "1"
else:
return M + "1" + "0"*(paddingBits-2+r) + "1"
else:
return M
A multi-rate padding adds a string
In the figure above note that there is a function
Step 0 of the the absorbing stage is an initizialization of step before applying the function
s = M1 + 0*c
where M1
is the block 0*r
, which is just equal to
Let xor
operation and
#M is the i-th block of bits
#s is the state at the (i-1)-th step
#r is the rate
def step(M,s,r):
xors = ""
for(i in range(r)):
xors += str(int(s[i])+int(M[i])-2*int(s[i])*int(M[i]))
newS = xors + s[r:]
return f(newS)
The for
cycle computes de xor between
This last subrutine is applied
Let
#s is the current state
#r is the rate
def squeeze_step(s,r):
sNew = f(s)
outterState = sNew[0:r]
return outterState, sNew
The function squeeze_step
is called until the length of the output is at least
#sk is the state at the end of the absorbe stage
#r is the rate
#l is the number of output bits
def squeeze(sk,r,l):
Z = sk[0:r]
s = sk
while len(Z) < l:
output_r, s = squeeze_step(s,r)
Z += output_r
return Z[0:l]
This concludes our brief explanation of the sponge construction.