# Disproving a Coincidence with Code Golf

## Table of Contents

In this post, we use code golf^{1} to prove that claims made by the
designers of some Russian standard cryptographic algorithms are
factually wrong. The content of this page is based on a joint work
with Xavier Bonnetain and Shizhu Tian [5].

## 1 A Seemingly Impossible Code Golf Challenge

How small of a function can you write that takes as input an integer
`x`

in \(\{ 0,1,...,255 \}\) and outputs `pi[x]`

where `pi`

is the table
given below? Here, "small" means that the corresponding source code
length *measured in bits* is short.

**Send me your best implementation in the language of your choice and I will publish it on this page!**

**It does not have to shorter than our best implementations.**

unsigned char pi[] = { 0xFC,0xEE,0xDD,0x11,0xCF,0x6E,0x31,0x16,0xFB,0xC4,0xFA,0xDA,0x23,0xC5,0x04,0x4D, 0xE9,0x77,0xF0,0xDB,0x93,0x2E,0x99,0xBA,0x17,0x36,0xF1,0xBB,0x14,0xCD,0x5F,0xC1, 0xF9,0x18,0x65,0x5A,0xE2,0x5C,0xEF,0x21,0x81,0x1C,0x3C,0x42,0x8B,0x01,0x8E,0x4F, 0x05,0x84,0x02,0xAE,0xE3,0x6A,0x8F,0xA0,0x06,0x0B,0xED,0x98,0x7F,0xD4,0xD3,0x1F, 0xEB,0x34,0x2C,0x51,0xEA,0xC8,0x48,0xAB,0xF2,0x2A,0x68,0xA2,0xFD,0x3A,0xCE,0xCC, 0xB5,0x70,0x0E,0x56,0x08,0x0C,0x76,0x12,0xBF,0x72,0x13,0x47,0x9C,0xB7,0x5D,0x87, 0x15,0xA1,0x96,0x29,0x10,0x7B,0x9A,0xC7,0xF3,0x91,0x78,0x6F,0x9D,0x9E,0xB2,0xB1, 0x32,0x75,0x19,0x3D,0xFF,0x35,0x8A,0x7E,0x6D,0x54,0xC6,0x80,0xC3,0xBD,0x0D,0x57, 0xDF,0xF5,0x24,0xA9,0x3E,0xA8,0x43,0xC9,0xD7,0x79,0xD6,0xF6,0x7C,0x22,0xB9,0x03, 0xE0,0x0F,0xEC,0xDE,0x7A,0x94,0xB0,0xBC,0xDC,0xE8,0x28,0x50,0x4E,0x33,0x0A,0x4A, 0xA7,0x97,0x60,0x73,0x1E,0x00,0x62,0x44,0x1A,0xB8,0x38,0x82,0x64,0x9F,0x26,0x41, 0xAD,0x45,0x46,0x92,0x27,0x5E,0x55,0x2F,0x8C,0xA3,0xA5,0x7D,0x69,0xD5,0x95,0x3B, 0x07,0x58,0xB3,0x40,0x86,0xAC,0x1D,0xF7,0x30,0x37,0x6B,0xE4,0x88,0xD9,0xE7,0x89, 0xE1,0x1B,0x83,0x49,0x4C,0x3F,0xF8,0xFE,0x8D,0x53,0xAA,0x90,0xCA,0xD8,0x85,0x61, 0x20,0x71,0x67,0xA4,0x2D,0x2B,0x09,0x5B,0xCB,0x9B,0x25,0xD0,0xBE,0xE5,0x6C,0x52, 0x59,0xA6,0x74,0xD2,0xE6,0xF4,0xB4,0xC0,0xD1,0x66,0xAF,0xC2,0x39,0x4B,0x63,0xB6 };

Why this table? Why do we want a small implementation? Is it even possible to find one? Read on!

## 2 Why this Challenge Matters

### 2.1 What is π?

π (as in the Greek letter) is a component used by the latest standard
symmetric cryptographic algorithms in Russia, namely the block cipher
Kuznyechik and the cryptographic hash function Streebog. It is what we
cryptographers call an **S-box**, i.e. a small non-linear function with
an input small enough that it is possible to specify said function
simply by providing all of its outputs. That is what the C array above
is: `pi[x]`

is equal to π(x).

Both Streebog and Kuznyechik are standards in Russia and at the IETF
(RFC 6986 and 7801 respectively). Streebog is also an ISO/IEC standard
and Kuznyechik might become one. In a previous paper on this S-box
[3], I found that it could be described by a very simple
algorithms which I called *TKlog*. This work and its context are
summarized on this page.

### 2.2 Is its TKlog Structure a Coincidence?

Since the publication of that structure, the designers of these algorithms have claimed that the presence of said structure was a mere coincidence during an ISO/IEC meeting [4]. They claim to have in fact generated it by picking random permutations and then keeping one with good enough cryptographic properties. More details about their claims can be seen in two internal ISO documents that were recently leaked:

- the first describes their generation process: memo-on-kuznyechik-s-box.pdf,
- the second is a summary of a discussion that took place
**after**the publication of the final decomposition [3]: meeting-report-for-the-discussion-on-kuznyechik-and-streebog.pdf.

However, the set of TKlogs is beyond tiny (it contains \(2^{82.6}\)
elements while there are \(256! \approx 2^{1684}\) permutations of \(\{
0,1,...,255 \}\)), meaning that their claim is *a priori* very hard to
believe. To put these unfathomable number into perspective: there are
about \(2^{265}\) atoms in the universe and a random permutation is a
TKlog with a probability of \(2^{82.6-1684} \approx 2^{-1601.4}\) which
is just under \((2^{-265})^6\). Suppose that you are participating in a
special lottery where you have to pick 1 atom in the whole universe,
and that you win if you guessed the right one. The probability of
obtaining a TKlog when choosing an 8-bit permutation uniformly at
random is a bit below the probability of winning this atomic lottery
*6 times in a row*. What I am trying to say is that the probability of
obtaining a TKlog by chance is *small*. Like, really, *really really*
small.

Thus, to try to reconcile my work with their claims of randomness,
the designers of π asserted that, for any permutation, it is possible
to find a simple structure implementing it. Thus, while the
probability of having a TKlog specifically is tiny, the probability of
having *some* structure is very high. Had they picked the next
randomly generated S-box, I would have found another equally unlikely
structure.

It sounds plausible! Indeed, suppose that you have a coin and want to
check if it is biased. To do this, you look at the number of tails you
get when tossing it 10000 times and find 4970. The probability that
you get *exactly* this number is quite small:
$$
\textrm{Pr}\left[\# \textrm{tails} = 4970 \right] = {10000 \choose 4970} 2^{-10000} \approx 0.0067 ~.
$$
But it is not that interesting. What would be much more meaningful in
this case is the probability that you get 4970 tails *or fewer*,
namely
$$
\textrm{Pr}\left[\# \textrm{tails} \leq 4970 \right] = \sum_{i=0}^{4970}{10000 \choose i} 2^{-10000} \approx 0.28 ~,
$$
which is actually quite high.

The situation would then be the same for the presence of a structure
in an S-box. Sure, each specific structure has a tiny probability
(like that of having exactly 4970 tails) but it is the case for the
structure of *all* the S-boxes. It is similar to the case of the coin,
having exactly 4971 or 4969 tails is also unlikely. But it doesn't
mean anything: it is in the end not that weird to have at most 4970
tails, and we cannot deduce that the coin is biased from the fact that
it yielded 4970 tails. For π, we similarly could not deduce that its
structure is not a coincidence from the fact that said structure has a
low probability.

Except this is completely wrong.

### 2.3 No, it's Not

As plausible as it may sound, the argument about π detailed above is
completely wrong because a random permutation does not have a
structure and *certainly not one as simple as a TKlog*.

To see why, we need to find a way to sort the different S-box
structures. If two structures can always be ranked (i.e. if we can
find a partial ordering of the S-box structures), then we can look at
probabilities that are far more meaningful: instead of the
probability that π has a *specific* structure (here, the TKlog), we
can instead look at the probability that π is *at least as structured
as a TKlog*. As in the example above with the coin, this would give us
a probability of having a structure like the one we found *or better*,
which would be far more informative.

And that is why we will code golf!

### 2.4 To Prove it, We Need a Small Implementation of π

The ordering we propose to use is very simple and takes inspiration
from the Kolmogorov complexity. Intuitively, if a function is "simple"
or "too structured" then it should be possible to implement it using a
short program. Here, short means that the program takes literally
little space, i.e. that it can be encoded with few bits. The length
of the smallest program is then an integer, and those are very easy to
order: 1 is smaller than 5 which is smaller than 47, etc. Identically,
a function that can be implemented on 400 bits is simpler than one
that needs at least 2000. Finding small implementations is precisely
the goal of code golf, which is why we need to grab our metaphorical
golf clubs. We must however be careful to choose a meaningful
language: if we just define a language such that `p()`

is a predefined
function that implements π then we haven't said much.

One problem remains: we can now *compare* the simplicity of
two functions by comparing the length of their smallest
implementation. But in order to say something about the simplicity of
a given function compared to all the others, we need some *absolute*
quantification of said simplicity. This implies bounding the length of
the program needed to implement a random permutation.

It is surprisingly simple to obtain a (very coarse) bound suited to our purpose. In fact, Claude Shannon used the same kind of argument to prove that almost all Boolean functions mapping n bits to 1 are as difficult to implement as the hardest ones [6]. Suppose that all strings of \(b\) bits are valid programs in the language of your choice. Then at most \(1+2+4+...+2^b = 2^{b+1}-1\) functions have an implementation at most \(b\) bits long. There are at most \(2^{b+1}-1\) such program so it is impossible that they correspond to \(2^{b+1}\) distinct functions or more.

Thus, in our case, if a permutation can be implemented by a program of length \(L\) then there are at most \(2^{L+1}\) permutations with an implementation as small as this, and the probability that a random permutation is that simple is at most equal to \(2^{L+1-1684}\). This bound is everything but tight! It assumes that all strings are valid programs corresponding to distinct permutations. It is not the case, so we have an upper bound—but that is all we need.

## 3 Implementations too Small to be Normal

We set out to find a small implementation of π, i.e. one which needs
much fewer than 1684 bits. We chose the C language: we hope you are
convinced that we did not temper with the C standard^{2} to allow
the small implementation described below. To push our approach
further, we also looked at ARM machine code as it lends itself well to
very short implementations.

Using the TKlog structure from [3] Xavier Bonnetain devised the following implementation. It is explained on this page.

p(x){unsigned char*t="@`rFTDVbpPBvdtfR@\xacp?\xe2>4\xa6\xe9{z\xe3q5\xa7\xe8",a=2,l=0,b=17;while(++l&&a^x)a=2*a^a/128*29;return l%b?t[l%b]^t[b+l/b]^b:t[l/b]^188;}

The program above contains 161 characters which are all ASCII, meaning that they can be encoded on 7 bits each. In total, our implementation is 161×7=1127 bits. We present other implementations in [5].

We then have that a random permutation is at least as simple as π with probability at most \(2^{1127+1-1684} = 2^{-556}\), i.e. roughly the probability of winning the atomic lottery twice in a row. It is more likely than winning it 6 times but it is still extremely unlikely.

This is only a bound on how unlikely this level of structure is when looking at the C language. If we instead look at the best implementation found by the golfers on stackexchange, namely recursive's Stax implementation, we obtain a program length of 464 bits bits and thus a probability bound of \(2^{464+1-1684} = 2^{-1219}\). It is much smaller than the probability of winning the atomic lottery 4 times in a row.

To put it this length into another perspective, let us compare π with the S-box of the AES. The shortest implementation of the AES S-box, which can also be found on stackexchange, is 60 ASCII characters long. It corresponds to a program length of 420 bits, which is of the same magnitude as the 464 bits of the shortest π implementation. It is not surprising that it has a small implementation: this S-box has a very strong mathematical structure that has always been public. In fact we can trace its root back to a Eurocrypt 1993 paper [7].

Overall, the fact a random permutation is as structured as π is incredibly unlikely. And I do literally mean "incredibly", i.e. that it should not be believed that such an unlikely event happened by chance.

## 4 Conclusion

There are only two possible conclusions from our results:

- the designers of π are
*incredibly*lucky, or - π was not designed in the way they claim.

**The probability of the first option is negligible. The presence of the TKlog is thus a deliberate decision from the designers.**

Finally, if you have a short implementation of π in some language, send it to me and I will put it with the others here!

## 5 Acknowledgement

I thank Xavier Bonnetain for his help when drafting this document and for his proofreading.

## 6 Updates

- 19 February 2020
- To this day, the designers of \(\pi\) have
maintained their claim of randomness.
Also, I updated the form of this page (mostly, new CSS).

## 7 Bibliography

- Alex Biryukov, Léo Perrin, and Aleksei Udovenko.
**Reverse-engineering the S-box of streebog, kuznyechik and STRIBOBr1**. In Marc Fischlin and Jean-Sébastien Coron, editors,*Advances in Cryptology – EUROCRYPT 2016, Part I*, volume 9665 of*Lecture Notes in Computer Science*, pages 372–402. Springer, Heidelberg, May 2016. link to eprint.iacr.org. - Léo Perrin and Aleksei Udovenko.
**Exponential S-boxes: a link between the S-boxes of BelT and Kuznyechik/Streebog**.*IACR Transactions on Symmetric Cryptology*, 2016(2):99–124, 2017. link to tosc.iacr.org. - Léo Perrin.
**Partitions in the S-Box of Streebog and Kuznyechik**.*IACR Transactions on Symmetric Cryptology*, 2019(1), 302–329, 2019. link to tosc.iacr.org. - Joseph Cox.
**Experts Doubt Russian Claims That Cryptographic Flaw Was a Coincidence**. Vice, Motherboard (8th of May 2019). link. - Xavier Bonnetain, Léo Perrin and Shizhu Tian.
**Anomalies and Vector Space Search: Tools for S-Box Reverse-Engineering**. link to eprint.iacr.org. - Claude Shannon.
**The synthesis of two-terminal switching circuits.***The Bell System Technical Journal*, 28(1):59–98, Jan 1949. - Kaisa Nyberg.
**Differentially uniform mappings for cryptography.***Eurocrypt 1993*, 55–64, 1993. link to springer.com

## Footnotes:

^{1}

The analysis I present in this note proves that π cannot be the output of a random generation using only the simplicity of its structure. As discussed in the description of said structure, it also has very peculiar cryptographic properties that interact in a special way with other components of the algorithms using this S-box. This alone should be sufficient to rule out a random generation. Still, it turns out that we don't even need these arguments, studying π "in a vacuum" can tell us everything we need.

^{2}

A compelling argument being that ANSI C89 is literally older than each of the authors of [5].