[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)