The challenge
Sixteen seems like a perfectly reasonable number of fingers.
The question, word for word Days 1 and 2:
Decode the assigned blob completely. What exact answer slug does its final non-empty decoded line instruct you to submit?
Answer format: word-word-word-NN, trimmed. Mastery: 13 blobs (Day 1 had 3, Day 2 had 8).
Reading the prompt: what it said we'd need
| Clue | What it pointed to | What I did about it |
|---|---|---|
| "Sixteen … fingers" | Base 16, hexadecimal. We count in tens because of ten fingers, so sixteen fingers means counting in sixteens | Day 1's decoder already reads plain hex. I added the other ways hex gets written |
| "Hex Appeal" (the title) | A pun on "sex appeal", confirming hex | — |
| The question is identical to Days 1 and 2 | A compounding day: Base64 (Day 1) and ROT13 (Day 2) are likely to come back alongside hex | Build on Day 2's solver |
| Day 2's Mastery mixed encodings per line | Day 3's Mastery would probably add a third line in the new encoding | The per-line decoding fix went in before Day 3 started (see below) |
Before starting: fixing Day 2's solver
Day 2's Mastery passed partly by luck. Each blob was two labelled lines with different encodings (Base64, then ROT13), splitting the sentence mid-word. The old solver ROT13'd the whole blob, which happened to work only because the slug sat in the ROT13 line.
The fix, made and tested before Hex Appeal was opened:
- Split each NN<TAB>payload line on its first tab and keep the payload's spaces exactly. The real Day 2 blobs needed this: one line started with a space, and another decoded to text ending in one. Stripping them glued words together.
- Decode each line by itself. For each line, try every decoder (and ROT13), up to 4 layers deep, and keep the most English-looking result. Fewer layers win ties.
- Join the decoded pieces in label order, then look for the instruction.
- Fall back to the old method if that finds nothing, so a single Base64 string split across lines still works.
Checked against all 8 real Day 2 Mastery blobs: each decoded as L01:base64 → L02:rot13 to the full sentence, giving the same answers the Game Master had accepted. 12 tests pass, including a new one with the slug in the Base64 line, which the old solver would have failed.
What was in the files
Every blob decoded to the familiar sentence: "Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: <slug>". As on Day 2, only the wrapping changed between modes:
| Mode | Delivered as | Raw format |
|---|---|---|
| Single Solve | blob., 224 B |
The whole sentence as one line of lowercase hex |
| Time Trial | blob., 220 B |
The same |
| Mastery | One zip of blob- (3,486 B) |
Three labelled lines per blob: 01 Base64, 02 ROT13, 03 hex |
The Single Solve blob, raw (start only) and decoded:
4e69636520776f726b2064…
Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: nimble-scooter-boulder-88
How to spot hex by eye: only 0-9 and a-f, an even length, and for English text lots of 6x and 7x pairs (lowercase letters are 0x61–0x7a) with 20 between words (a space). 4e 69 63 65 is "Nice".
A Mastery blob: the sentence split mid-word across three encodings, one per earlier day (the hex line is shortened here):
01<TAB>TmljZSB3b3JrIGRlY29kaW5nIHRoaXMgd2FybXVwISBUbyBz
02<TAB>byir, fhozvg guvf rknpg nafjre gb gu
03<TAB>652047616d65204d6173…
| Line | Encoding | Decodes to |
|---|---|---|
01 |
Base64 (Day 1) | "Nice work decoding this warmup! To s" |
02 |
ROT13 (Day 2) | "olve, submit this exact answer to th" |
03 |
Hex (Day 3) | "e Game Master: witty-harbor-ripple-45" |
The slug was in the hex line in every one of the 13 blobs. Without the per-line fix, this Mastery run would have failed.
Single Solve: CORRECT in 61 seconds
Started at 14:35:16 UTC. blob.txt was downloaded and its SHA-256 matched (8a5302f0…92b8). It was one hex layer, giving nimble-scooter-boulder-88. CORRECT at 14:36:17, flag 7bb75124…efee. Most of the minute went on writing the Day 3 solver and its tests.
The solver
Our Day 3 solver loads Day 2's solver by path, so it inherits Day 1's decoders, ROT13, and the per-line decoding. It adds one decoder, hex-loose, for hex written with prefixes or separators, which Day 1's plain-hex step rejects:
| Written as | Example for "Ni" |
|---|---|
| Plain (Day 1 already handled it) | 4e69 |
0x prefixes |
0x4e 0x69 |
\x escapes |
\x4e\x69 |
| URL encoding | %4E%69 |
| Separated | 4e:69, 4e,69, 4e 69 |
None of these turned up in Hex Appeal, but they're the forms real payloads use, and a later warmup might.
7 tests, all passing before any timed run:
- plain hex;
- uppercase hex wrapped over several lines;
- all five prefixed or separated forms;
- hex mixed with ROT13 and Base64, in both orders;
- a per-line blob with a 0x line and a ROT13 line;
- plain hex left to Day 1's step;
- garbage, which it refuses.
Time Trial: 1.66 s of a 6-second clock
started_at 2026-10-07T14:38:07.545Z deadline 2026-10-07T14:38:13.545Z
artifact blob.txt 220 bytes sha256 8f182fc60cf319f4… (checked)
message: jovial-island-copper-93
start 516 ms
artifact 385 ms
solve 0 ms
submit 760 ms
TOTAL 1661 ms
result CORRECT flag d4b764c5…31dc
Plain hex again, one layer. Played entirely through the pairing token, with the Homebase off.
Mastery: 2.86 s of 7 s, first attempt
started_at 2026-10-07T14:42:04.149Z deadline 2026-10-07T14:42:11.149Z
artifact warmups-day-03-mastery.zip 3486 bytes sha256 38e8a977cb7cb066… (checked)
set1.message: witty-harbor-ripple-45
…
set13.message: dashing-garden-whale-40
start 1796 ms
artifact 371 ms
solve 4 ms
submit 691 ms
TOTAL 2863 ms
result CORRECT flag 325492ee…5ff5
Every blob decoded as L01:base64 → L02:rot13 → L03:hex. The start call took 1.8 s, about three times its usual 500–600 ms; Looks Can Be Deceiving's Mastery start was similarly slow (1.75 s). It looks like Mastery starts cost the server more (it builds the bundle). The margin was still over 4 seconds.
Time to solve
All three modes were solved on 2026-10-07 by 14:42:07 UTC, 6 min 51 s after the first start (the per-line fix to Day 2's solver was done beforehand). The Single Solve took 61 s, and the Time Trial (1.66 s of 6 s) and the Mastery (2.86 s of 7 s) each went through on the first submit.
Takeaways
- Fix what passed by luck before it matters. Day 2's Mastery answers were right for the wrong reason. Fixing that first meant Day 3's Mastery, with the slug in a line the old solver couldn't have reached, passed on the first attempt.
- The warmups compound one line at a time. Day 2 had 2 lines (Base64, ROT13), Day 3 had 3 (plus hex). Day 4 will probably have 4, with that day's new encoding as the last line. The solver only needs the new decoder added.
- Keep whitespace when a payload is split. Pieces of a split sentence carry its spaces at their edges. Trimming each piece corrupts the join.
- Score candidates; don't trust the first decode. Hex is also valid Base64 and Base32, and ROT13 always "succeeds". Picking the most English-looking result, with the fewest layers, chose the right decoding for every line.
- Mastery start calls are slower. Both Mastery starts on 2026-10-07 took about 1.8 s. With 5–7 s clocks that's fine, but it matters if a later clock gets much shorter.