21 bytes · base 256 · one integer
This card is a 51-digit number. Watch it resolve.
105784397473850395008567252507661666543031051708773
The whole trick
There is no encryption here, and no lookup table. The message is being shown in a different base, and every step is reversible arithmetic you could do by hand if you had the patience.
A computer stores "Happy birthday, Jamie" as 21 bytes, and a byte is just a
number from 0 to 255. A sequence of values that each run 0–255 is the definition of
digits in base 256 — so the whole string can be read as a single enormous number.
Scale that from 2 bytes to 21 and you get a 51-digit number, because 256²¹ lands around 10⁵⁰. That is the number at the top of this card.
Byte 0 through byte 20
Hex is base 16, and 256 = 16², so exactly two hex digits encode one byte. The boundaries line up perfectly, which is why the message becomes readable to anyone who knows a little ASCII. The 51-digit decimal form is deliberately the least legible representation — that is what makes it a gift instead of a note.
0x48 is 72 is H. 0x20 is 32 is a space. Same bits,
three notations.
Reading it back
Going back the other way is .to_bytes(21, 'big') followed by .decode().
Those two arguments exist because a bare integer has lost the only two facts that base
conversion can't recover on its own.
21
How many digits to produce. The number doesn't know it "should" be 21 bytes wide.
>>> n.to_bytes(20, 'big')
OverflowError: int too big to convert
>>> n.to_bytes(24, 'big')
b'\x00\x00\x00Happy birthday, Jamie'
Too few and it genuinely doesn't fit. Too many and you get harmless leading zeros — the same as writing 037 for 37.
'big'
Which end holds the most significant digit. Big-endian puts it first, the way we write numbers down.
>>> n.to_bytes(21, 'little')
b'eimaJ ,yadhtrib yppaH'
Flip it and the birthday wish arrives backwards, which is its own kind of party trick.
Your turn
As one base-256 integer
Same value, base 16
Byte length · decimal digits
This runs on JavaScript's BigInt, for the same reason the original fits on one
line in Python: both languages have arbitrary-precision integers, so a 51-digit value is as
unremarkable to them as 7.
Runnable
python3 -c "print((105784397473850395008567252507661666543031051708773).to_bytes(21,'big').decode())"
The outer quotes have to be double, because 'big' already claims the single ones.
Swap them and your shell will eat the line before Python ever sees it.
Bonus round
Three lines. Run it and it prints itself — character for character identical,
except the counter has gone up by one. The %r is doing the real work: it quotes
the string so the string survives reproducing itself.
runs = 0 s = 'runs = %d\ns = %r\nprint(s %% (runs + 1, s)) # happy birthday, Jamie' print(s % (runs + 1, s)) # happy birthday, Jamie
Because the output is also a valid program, you can pipe it into itself. Every stage in the pipe is the same program reading the previous one's output, and the only thing that changes is the number:
$ python3 bday.py | python3 | python3 | python3 runs = 4