AES

FIPS 197 was announced on 26 November 2001, standardising Rijndael by Joan Daemen and Vincent Rijmen. The part worth building is the substitution table: every implementation on the internet has it typed in as 256 hexadecimal numbers, and a typed table is exactly the thing that can be wrong without anything noticing. This page does not type it. It derives the table from the rule the standard states, and then checks the whole cipher against the standard's own worked example.

Every byte that comes out depends on every byte that went in

1 The substitution table, derived rather than typed

These sixteen values were computed when this page loaded, from the rule the standard states rather than from a table anybody typed. They are the first sixteen of 256.

2 One round, and where every byte of it came from

A block of sixteen bytes, exclusive-ored with the first round key and then put through that table one byte at a time. Every byte below came out of the table above.

3 Ten rounds, against the standard's own worked example

Ten rounds of substitute, shift, mix and add. The standard prints the state after every one of those steps for this exact block and key, which is what the checks at the bottom compare against.

4 Flip one input bit, and count what moved

Now change one bit of the input and encrypt again. Not one byte: one bit. The marked bytes below are the ones that came out different.

These ran in this browser when the page loaded. Each claim, whether it held, and the number behind it. The expected values come from FIPS 197, archived and read rather than quoted from memory.

Each claim, whether it held, and the values behind it
claimheldmeasured
The substitution table is derived here, and its first row is the standard'syesderived 637c777bf26b6fc53001672bfed7ab76
And it is a permutation: every byte appears exactly onceyes256 distinct values out of 256
Every non-zero byte times its inverse is one, in the field the standard namesyeschecked all 255 of them
The whole cipher reproduces the standard's worked exampleyescomputed 3925841d02dc09fbdc118597196a0b32
No input bit leaves the output unchanged, over all 128 of themyes0 of 128 changed nothing
And flipping one input bit moves about half the output bitsyesmean 64.02 of 128, range 48 to 78

What is real here, and what is not

The substitution table is not written down anywhere on this page

Every implementation of AES you will find has the table typed in as 256 hexadecimal numbers, and a typed table is the thing this studio has been caught by before: exchange two rows and every structural test still passes while the output is wrong. So this page derives it, when it loads, from the rule the standard states: the multiplicative inverse in the field the standard names, then an affine transform. The tests check the derived table is a permutation of every byte, and check the source file for a typed table so that somebody cannot quietly put one back.

The cipher is checked against the standard's own example, state by state

FIPS 197 prints the value of the state after every step of an AES-128 encryption in its Appendix B. The tests read those out of the archived standard and compare them against this page's own intermediate states: thirty-one of forty match verbatim and every one of the eleven round keys does. The nine that do not are bytes the scan's text layer dropped rather than disagreements. The count is printed rather than rounded up to a pass, because a check that quietly compared twelve of them would look exactly the same from outside. What is NOT checked is a known-answer vector: the 2023 update to the standard removed Appendix C's example vectors in favour of a reference to vectors maintained elsewhere, and its own change log says so, so asserting one against this document would be asserting something it no longer contains.

Only AES-128, and only encryption

One key length, ten rounds, no decryption, no modes. A block cipher on its own encrypts sixteen bytes and nothing else; everything that makes it usable on a real message, the mode of operation and the initialisation vector and the authentication, is absent here and is where most real failures actually happen. This page is about the sixteen bytes.

This is not a secure implementation and is not meant to be one

It is written to be read, which is the opposite of what a cipher implementation is normally written for. There is no constant-time anything: the table lookups and the field multiplication both branch and both are timing side channels, which is a real class of attack on real AES and is the reason production implementations use hardware instructions. Do not take this file and use it.

The avalanche is measured over every input bit

The roster describes this machine as one where every byte out depends on every byte in. That is a measurable statement, so it is measured rather than repeated: each of the 128 input bits is flipped in turn and the number of output bits that move is counted. The mean is about 64 of 128, which is half, and the check also asserts that no input bit leaves the output untouched.

The date is the standard's announcement

FIPS 197 was announced on 26 November 2001. Rijndael was selected the year before and designed years earlier again, and the chronology takes the standard because that is when this became the thing everybody uses.

No sound

Nothing here has a duration.

Sources