TEA Cipher Avalanche
Ciphers & Bit Tricks
The 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 to focus, then watch. 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.