TEA Cipher Avalanche
Ciphers & Bit TricksThe Super Nintendo runs 32 rounds of the
Tiny Encryption Algorithm
to paint a 16×16 tile grid: each tile is coloured by bit 0 of
TEA(tile_index, key_variant). The multiplier cycles through 16 keys that each
differ by exactly one bit — a live demonstration of the
avalanche effect.
The hot loop uses only 32-bit <<, >>, +, and
^ — no multiply, no divide. Compiled with the
llvm-mos-based 65816 toolchain
(+mos-a16).
Self-running demo — 16 key variants cycle automatically, each differing by 1 bit. (Boot holds while the gate CRC computes.)
Click the screen, then play. (Tab away and it pauses.)
What it is
Each tile at position (tx, ty) is encrypted as plaintext
{ tx + ty*16, key_variant } using the fixed 128-bit key.
Bit 0 of the output's first word determines the tile colour: black (0) or orange (1).
Tiles fill at 4 per frame; once all 256 are painted, the demo holds briefly then
advances to the next key variant.
// TEA round — 32 iterations, no multiply: sum += 0x9E3779B9u; // Fibonacci/golden-ratio constant v0 += ((v1 << 4) + k[0]) ^ (v1 + sum) ^ ((v1 >> 5) + k[1]); v1 += ((v0 << 4) + k[2]) ^ (v0 + sum) ^ ((v0 >> 5) + k[3]); // Under +mos-a16: <<4 = 4×ASL+ROL inline, + = rep/sep bracketed ADC
Compiler stress-test #30 — 32-bit add/XOR/shift, multiply-free
A Round 2 demo targeting the "variable-count shifts" corner of the coverage map.
TEA's shift counts are compile-time constants (4, 5) but the 32-bit shift lowering
is the corner no prior demo exercises — either inline ASL+ROL chains or
__ashlsi3/__lshrsi3 libcalls. This build inlined them.
| Corner | What it exercises |
|---|---|
| TEA round — no multiply | Each of 32 rounds computes: v0 += ((v1<<4) + k[0]) ^ (v1+sum) ^ ((v1>>5) + k[1]) and symmetrically for v1. Every operation is a 32-bit left-shift-by-4, right-shift-by-5, add, or XOR — not a single multiply or divide. This is the codegen corner all prior demos skip: dense 32-bit arithmetic without any libcall. |
| Constant shifts, inline expansion | The <<4 and >>5 on uint32_t compile to inline ASL+ROL/LSR+ROR chains under +mos-a16 at -Os — the disasm gate confirmed __mulsi3=0, shift_libcalls=0, rep/sep=22. The 22 rep/sep pairs come from every 32-bit add and XOR needing a REP #$20 (switch to 16-bit A) / SEP #$20 (back to 8-bit A) bracket for each 16-bit half. |
| Avalanche visualised | 256 canvas tiles are coloured by bit 0 of TEA(tile_index, key_variant). Each of 16 key variants differs from the previous by exactly one key bit. Correct TEA produces completely uncorrelated patterns for each key — a single flipped bit scrambles all 256 output bits. If the 32-bit arithmetic miscompiles, the pattern shows structure or wrong correlation. |
| Bit-exact across all modes | All arithmetic is explicit uint32_t with no floating point. The gate CRC encrypts 8 fixed plaintexts and folds v[0]^v[1] → 0xDF0E. Confirmed host == default == +mos-a16 == +mos-xy16 on bsnes-jg. No compiler bug found. |
Written in C with the llvm-mos 65816 toolchain. Hit Verify fidelity to
reproduce the build gate's WRAM assert (gate CRC 0xDF0E) live in this tab.
Disasm gate: __mulsi3=0, shift_libcalls=0, rep/sep=22.
No compiler bug found — 32-bit shift/add/XOR codegen correct across all modes.