[HN Gopher] Hiding messages in a deck playing cards
___________________________________________________________________
Hiding messages in a deck playing cards
Author : ashfn
Score : 94 points
Date : 2025-07-18 14:41 UTC (3 days ago)
(HTM) web link (asherfalcon.com)
(TXT) w3m dump (asherfalcon.com)
| ashfn wrote:
| Hey all, I found a cool way to convert text into a specific order
| of a deck of playing cards. I detailed the instructions of how it
| works in the blog post but a brief overview would be that it uses
| Lehmer codes which allow you to uniquely identify each
| permutation of a set i.e. each of the many many ways a deck of
| cards can be shuffled/arranged
| pmarreck wrote:
| TIL about Lehmer codes... and "poker encoding" ;)
|
| (I just prefer poker to solitaire...)
|
| Someone else mentioned that the orientation of the cards (up or
| down) and possibly even the front-back facingness of the card
| (facing up, facing down) would add another 2 possible bits to
| the available encoding space. (Of course, at that point you'd
| have to also encode which side of the whole deck is the
| "top"...)
|
| My own thought was to add par2 to make it robust against small
| errors... at the cost of some transmission space!
| hungmung wrote:
| > Of course, at that point you'd have to also encode which
| side of the whole deck is the "top"...)
|
| An asymmetrical joker could indicate which short edge is
| "right way up", while also indicating which card is the first
| or last of the deck.
| ashfn wrote:
| Yeah that would make an interesting addition. I was thinking
| about error correction so if you swapped two cards it would
| be okay but was struggling with how it would work, but I
| think it would be quite fun to add :)
| russellbeattie wrote:
| > _"...which side of the whole deck is the 'top'..."_
|
| A dark line drawn across the top of the deck would be enough.
| Though it would ruin the stealth factor of the cards.
|
| Also, the pattern on the back of some playing decks isn't
| symmetrical, so that could be used as well.
| istjohn wrote:
| Decode it both ways and see which isn't gibberish.
| SetTheorist wrote:
| Reminds me of the playing-card based encryption system designed
| by Bruce Schneier for the novel Cryptonomicon .
|
| https://en.wikipedia.org/wiki/Solitaire_(cipher)
| zahlman wrote:
| Despite appearing to have perfectly ordinary structured static
| HTML content (aside from the fact that it spams things like <span
| style="font-weight:bold"> instead of using some basic CSS
| properly), without JavaScript I only see a solid-colour
| background.
|
| Anyway, this doesn't offer a whole lot of storage:
| $ python -c 'print(sum(__import__("math").log2(x) for x in
| range(1, 53)) // 8)' 28.0
| pmarreck wrote:
| https://deckcrypt.github.io/
|
| 45 characters according to the blog post and this demo
| throwanem wrote:
| 45 code points in a custom 5-bit encoding representing 32
| characters; 28 bytes (with 1 to 4 bits left over) of 8-bit
| ASCII.
| throwanem wrote:
| 28 bytes out of ~225 bits, sure. (I compute 228 bits, but
| precision gets funny with quantities so large. Interestingly,
| an emulated TI-86 and a real TI-89 Titanium returned different
| answers; the latter wasn't even divisible by 8!)
|
| For movie-plot '52 pick-up' that's not so bad, especially if
| used to encode something like a key for the "Solitaire"
| cryptosystem, mentioned nearby, wherein the same deck can in
| turn be reconfigured and manipulated to generate an arbitrary-
| length keystream for application to a longer message
| transmitted under separate cover.
| lxgr wrote:
| Nice! But why just hide one message if you can run an entire
| encryption algorithm with the deck? :)
|
| https://en.wikipedia.org/wiki/Solitaire_(cipher)
| empath75 wrote:
| Por que no los dos? One deck has the encrypted message, the
| other deck has the key.
| a_t48 wrote:
| You should be able to get another 45 bits or so by also using the
| orientation of the cards (everything except non face card
| Diamonds).
| pg_bot wrote:
| You could also add face up or down.
| throwanem wrote:
| You might squeeze a tag bit for the deck out of the 7*,
| depending on the pack design.
| fsckboy wrote:
| > _you might squeeze a tag bit for the deck out of the 7*_
|
| awww, youuuuu!! hugz!
|
| _" The Seven of Diamonds meaning in a Tarot reading can show
| that you will be surrounded by love."_
|
| (i was looking it up to find what the different cards looked
| like and found that)
|
| and yes "you and I might squeeze a bit" later
| throwaway290 wrote:
| is it just me or that comment unexpectedly lives up to your
| username
| throwanem wrote:
| Good to see you're enjoying yourself, whoever you are.
| da_chicken wrote:
| The 2, 4, 8, and 10 of all suits are typically rotationally
| symmetrical.
| joshvm wrote:
| Only if your deck has a rotationally symmetric back. A lot of
| decks are oriented with pictures or logos. Tarot decks almost
| always do to allow inverted readings (and you'd get a few
| more bits out from the major arcana).
| ComplexSystems wrote:
| Good stuff. You could get _much_ better bandwidth than this by
| tokenizing and using something like a Huffman or arithmetic code
| on token frequencies. As a simple example, if you set your tokens
| to be all English words - let 's say there are between 500k and 1
| million - that's about 9-10 bits per word. I am sure you could do
| much better than this as well
| ashfn wrote:
| That sounds very interesting, I'll look into it thanks :)
| avidiax wrote:
| You can get much better than that by taking a well-known LLM
| model and encoding a series of offsets from the most likely
| sequence of tokens, especially if you are OK with the message
| being slightly different.
|
| https://arxiv.org/abs/2306.04050
|
| https://bellard.org/ts_zip/
| mrdoornbos wrote:
| I've done Pontifex from Cryptonomicon on a Commodore 64 for fun.
| Bruce Schneier came up with it.
| https://imapenguin.com/2021/05/making-and-breaking-ciphers-o...
| sltkr wrote:
| Pet peeve: the blog post mentions _decimal_ and _denary_ several
| times, but in reality, there are no decimal numbers involved in
| any part of the computation.
|
| This is a common mistake made by people who haven't fully
| internalized the distinction between numbers (which have no
| intrinsic representation) and _numerals_ which are the encodings
| of numbers.
|
| When you are converting a permutation to its index, you are not
| converting to _decimal_, you are converting it to an integer.
| That integer has no intrinsic base. In Python (and the linked C++
| code) that integer will be internally represented in binary (or a
| base that is a higher power of 2) and the corresponding decimal
| representation is generated only when printing.
|
| So functions like decimalToFactoradic() should really be named
| integerToFactoradic(), etc.
| zzo38computer wrote:
| There are other five bit character sets as well, such as the
| 5-bit Baudot character set and the 5-bit Zork character set. You
| could also use variable bits characters, or other bases of
| numbers.
|
| You can also use other decks, e.g. with tarot cards you will have
| 78 cards rather than only 52 cards, and can make a longer
| message.
|
| Other comments on here had mention doing other things such as
| face-up vs face-down cards.
| russellbeattie wrote:
| How about just assigning a number to every sentence in every
| language known to man, and using the absurdly huge number of deck
| combinations to identify them?
|
| Impractical, but possible.
| cwmoore wrote:
| 225 bits
| praptak wrote:
| Encoding with common objects was (and maybe still is) actually
| used in practice by actual spies, see CIA shoelace code.
| ilcavero wrote:
| A while ago I made an interactive demonstration of how encoding
| with factoradic works https://ilcavero.github.io/ seems like I
| found someone else who thought it was a fun thing to demo
___________________________________________________________________
(page generated 2025-07-21 23:01 UTC)