Foursquare Cipher
The digraph cipher that's genuinely fun to bury clues in
- encrypted_txt
Foursquare is a classical cipher with a genuinely good payoff for ARGs: it encrypts two letters at a time (digraphs), which smears out the single-letter frequency patterns that make simple substitution ciphers trivially crackable. If you've ever hidden a message with a Caesar shift and watched a solver crack it in thirty seconds, this is the step up that still feels like a puzzle rather than homework. It's powered by the secretpy library, the same engine behind most of the pack's classical ciphers.
How it works
The cipher uses four 5×5 grids of letters - a 2×2 arrangement of Polybius squares. Two of the squares (top-left and bottom-right) hold the plain alphabet; the other two hold alphabets scrambled by two keywords, key_1 and key_2. To encrypt a pair like "hi," you find the H in the plain square and the I in the plain square, then read the letters at the opposite corners of the rectangle they form - one from the key_1-mixed square, one from the key_2-mixed square. Two keywords means two independent scrambling alphabets, which is what makes it stronger than Playfair against frequency analysis.
The inputs that matter
text- the message, defaults to "Hello World!".key_1andkey_2- the two keywords, each in the alphabet's language. These are the actual secrets. In the classic Foursquare setup, the solver needs both keywords to decrypt, and having two lets you hand out one key to some people and the other to others for partial messages. Keyword letters just get used to build the mixed alphabets, so spaces and punctuation are ignored.alphabet- defaults toENGLISH; you can supply a custom alphabet string, or the name of a predefined one from secretpy'salphabets.py. The tooltip spells out the accepted format (abcdefconnected). This matters more than it looks: classical ciphers are language-specific, so yourtexthas to be in the alphabet's language or you'll encrypt nonsense.mode- on isencrypt, off isdecrypt.keep_formatting- on preserves the message's spaces/punctuation/case in the output; off strips everything and lowercases. For hiding clues,keep_formattingon makes the output look like real text; off gives you the classic solid-ciphertext block.
The output
encrypted_txt(STRING) - the ciphertext (or plaintext, in decrypt mode). Wire it anywhere a string flows, or save it out. Since the underlying alphabet is 25 letters (I/J combined, per the standard 5×5 square), the output is clean uppercase letters.
Installing it
Part of the ComfyUI ARG Toolkit:
cd ComfyUI/custom_nodes
git clone https://github.com/AzelusLightvale/ComfyUI-ARG-Toolkit
Restart ComfyUI, or grab it via ComfyUI Manager ("ComfyUI ARG Toolkit"), which installs secretpy along with the pack's other dependencies.
Where people get burned
- Empty keywords. Both
key_1andkey_2default to empty strings. With no keywords the mixed squares come out... standard, which technically encrypts nothing. Fill both keys in or the "cipher" is about as secure as a screen door. - Wrong language. Feed Cyrillic text with the English alphabet and you'll get errors or garbage. Match the alphabet to the message.
- Odd-length messages. Digraph ciphers want even-length input; a dangling single letter usually gets dropped or padded depending on the library. If your decrypted message looks short by a character, that's the classic culprit.
The Foursquare node is where the pack's "poor-man's cryptanalysis lab" framing starts to make sense - encrypt a clue with two keywords, hide the keywords in different parts of the trail, and let the solver do the rectangle work.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| text | STRING | Hello World! | — |
| alphabet | STRING | ENGLISH | Input your alphabet here. If left blank, uses the alphabet default to the cipher. Uses standard connected format ('abcdef'), but can also accept the alphabets defined in secretpy in alphabets.py. |
| mode | BOOLEAN | true | Toggle between encrypting or decrypting a message. |
| keep_formatting | BOOLEAN | true | Toggle between preserving the format of the message or remove all spaces, punctuations, and convert to lowercase. |
| key_1 | STRING | Accepts any text (or alphabet) in the alphabet's language as the first key to decrypt/encrypt. | |
| key_2 | STRING | Accepts any text (or alphabet) in the alphabet's language as the first key to decrypt/encrypt. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| encrypted_txt | STRING | — |