Keccak-f

This table computes the Keccak-f[1600] permutation.

Keccak-f Permutation

To explain how this table is structured, we first need to detail how the permutation is computed. This page gives a pseudo-code for the permutation. Our implementation differs slightly -- but remains equivalent -- for optimization and constraint degree reasons.

Let:

  • be the sponge width ( in our case)

  • be the number of Keccak rounds ()

  • a vector of round constants of size

  • be the input of the permutation, comprised of 64-bit elements

The first step is to reshape into a matrix. We initialize the state of the sponge with :

We store in the table, and subdivide each 64-bit element into two 32-bit limbs. Then, for each round , we proceed as follows:

  1. First, we define . We store as bits in the table. This is because we need to apply a rotation on its elements' bits and carry out xor operations in the next step.

  2. Then, we store a second vector in bits, such that: .

  3. We then need to store the updated value of : Note that this is equivalent to the equation in the official Keccak-f description: .

  4. The previous three points correspond to the step in Keccak-f. We can now move on to the and steps. These steps are written as: where is the bitwise cyclic shift operation, and is the matrix of rotation offsets. We do not need to store : 's bits are only a permutation of 's bits.

  5. The step updates the state once again, and we store the new values: Because of the way we carry out constraints (as explained below), we do not need to store the individual bits for : we only need the 32-bit limbs.

  6. The final step, , consists in updating the first element of the state as follows: where Since only the first element is updated, we only need to store of this updated state. The remaining elements are fetched from . However, because of the bitwise operation, we do need columns for the bits of .

Note that all permutation elements are 64-bit long. But they are stored as 32-bit limbs so that we do not overflow the field.

It is also important to note that all bitwise logic operations (, and ) are checked in this table. This is why we need to store the bits of most elements. The logic table can only carry out eight 32-bit logic operations per row. Thus, leveraging it here would drastically increase the number of logic rows, and incur too much overhead in proving time.

Columns

Using the notations from the previous section, we can now list the columns in the table:

  1. columns to determine which round is currently being computed. when we are in the -th round, and 0 otherwise. These columns' purpose is to ensure that the correct round constants are used at each round.

  2. column which stores the timestamp at which the Keccak operation was called in the cpu. This column enables us to ensure that inputs and outputs are consistent between the cpu, keccak-sponge and keccak-f tables.

  3. columns to store the elements of . As a reminder, each 64-bit element is divided into two 32-bit limbs, and comprises elements.

  4. columns to store the bits of the vector .

  5. columns to store the bits of the vector .

  6. columns to store the bits of .

  7. columns to store the 32-bit limbs of .

  8. columns to store the bits of .

  9. columns to store the two limbs of .

In total, this table comprises 2,431 columns.

Constraints

Some constraints checking that the elements are computed correctly are not straightforward. Let us detail them here.

First, it is important to highlight the fact that a between two elements is of degree 2. Indeed, for , the constraint is , which is of degree 2. This implies that a between 3 elements is of degree 3, which is the maximal constraint degree for our STARKs.

We can check that . However, we cannot directly check that , as it would be a degree 5 constraint. Instead, we use for this constraint. We see that: This implies that the difference is either 0, 2 or 4. We can therefore enforce the following degree 3 constraint instead:

Additionally, we have to check that is well constructed. We know that should be such that . Since we do not have the bits of elements but the bits of elements, we check the equivalent degree 3 constraint:

Finally, the constraints for the remaining elements, and are straightforward: is a three-element bitwise where all bits involved are already storedn and is the output of a simple bitwise with a round constant.