toycrypt

complete

· CS + Security

stack
C99
links

Do not use this. It is not constant-time, it has not been audited, and it exists to be read rather than linked against. Use libsodium.

A genuine crossover entry: the algorithms are computer science, the reason anyone cares about implementing them correctly is security. Dropping either category would misrepresent it — which is exactly the test for listing two.

Why write it

Reading the AES specification is not the same as implementing it. The round structure looks obvious on paper and stops looking obvious the moment you write MixColumns and get plausible-looking garbage out.

static void mix_columns(uint8_t state[4][4]) {
    for (int c = 0; c < 4; c++) {
        uint8_t a0 = state[0][c], a1 = state[1][c];
        uint8_t a2 = state[2][c], a3 = state[3][c];

        state[0][c] = xtime(a0) ^ (xtime(a1) ^ a1) ^ a2 ^ a3;
        state[1][c] = a0 ^ xtime(a1) ^ (xtime(a2) ^ a2) ^ a3;
        state[2][c] = a0 ^ a1 ^ xtime(a2) ^ (xtime(a3) ^ a3);
        state[3][c] = (xtime(a0) ^ a0) ^ a1 ^ a2 ^ xtime(a3);
    }
}

That xtime is multiplication by 2 in GF(2⁸) — a left shift plus a conditional XOR with 0x1b when the high bit was set. Once that clicks, the rest of the cipher stops being a diagram and starts being arithmetic.

Where it stops

The timing side channel is the interesting part, and the part I did not solve. The S-box lookup is table-driven, so access patterns depend on the key, and cache timing leaks them. Making it constant-time means bitslicing, which is a substantially harder project than the one I set out to do.

That gap is the honest lesson: a correct implementation and a safe implementation are different achievements, and only the first one is a weekend.