Affine Cipher
A Little Math Goes a Long Way (If the Key Cooperates)
- encrypted_txt
The Affine cipher is what happens when someone looks at a Caesar shift and thinks "we can do better with a line equation." Instead of shifting every letter by a fixed amount, it maps each letter to (a × position + b) mod alphabet_size - one multiplicative step, one additive step. Two knobs, marginally more security, and a far more interesting puzzle. In the ARG Toolkit it's the classical cipher that feels like it was designed by someone who actually thought about the math, because the two keys have very different personalities.
The personality difference matters: key_1 is the multiplicative part, and it must be relatively prime to the alphabet length (no common factors). With a 26-letter alphabet, that means key_1 has to be one of 1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, or 25. Pick something like 4, which shares a factor of 2 with 26, and letters start mapping to the same outputs - the cipher stops being reversible and your decrypt turns to mush. key_2 is the additive part and is far more forgiving: any integer from 0 to alphabet length minus 1 works, think of it as a starting index. Defaults are key_1 = 7 and key_2 = 8, which are valid for English.
The inputs that matter
key_1(INT) - the multiplicative key. The node's tooltip calls out the relatively-prime requirement. This is the one that'll reject you.key_2(INT) - the additive key. Forgiving by design.mode- encrypt/decrypt toggle (on = encrypt).text,alphabet,keep_formatting- the standard classical-cipher kit, with alphabet defaulting toENGLISH.
Output is the usual single encrypted_txt STRING.
A word on the validation
The source's key validation is... enthusiastic. It tries to verify your key_1 against the alphabet size, and the check as shipped has quirks - it can throw an error for values that are actually fine, and its internal gcd math isn't quite the textbook version. What this means in practice: don't fight the node. If it rejects a key_1, pick one of the coprime values listed above (7, 11, 17, 23 are all safe bets) and move on. The node's math on the actual encryption side is correct; it's the guard at the door that's a little overzealous.
Where people get burned
Beyond the coprime rule, the classic failure is cross-validating with an online tool and getting a different result. Affine implementations disagree on whether a=1, b=0 is "identity" or whether the alphabet starts at 0 or 1 - the pack lowercases and strips your input in shared preprocessing, which changes what you're comparing. If your output doesn't match dCode, check keep_formatting and the case of your input before suspecting the node. And remember decrypt needs the same two keys as encrypt; one digit off in key_1 and the whole round-trip is garbage, no error, no mercy.
Installing it
Like every node in this pack, it comes with the ARG Toolkit:
cd ComfyUI/custom_nodes
git clone https://github.com/AzelusLightvale/ComfyUI-ARG-Toolkit
Restart ComfyUI and find it under ARG Toolkit → Cryptography → Classical. Or ComfyUI Manager → search "ComfyUI ARG Toolkit" → Install. The classical ciphers depend on secretpy, handled by Manager (or pip install -r requirements.txt for manual clones). Pure Python, no models.
Troubleshooting
- Node refuses key_1 → it's not coprime with 26. Use 7, 11, 17, or 23.
- Decrypt is garbage → key mismatch, or you changed a key between encrypt and decrypt.
- Result differs from a website → flip
keep_formattingand match the case conventions; implementations differ there, not in the core math.
Affine is a lovely intro cipher and a staple of puzzle ciphers because the "crack" involves a tiny bit of modular arithmetic - perfect difficulty for an ARG step that should reward a solver who paid attention in math class.
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 | INT | 7 | The multiplicative part of the Affine key. Allows only numbers with no common factors to the alphabet length (relatively prime). |
| key_2 | INT | 8 | The additive part of the Affine key. Allows every integer from 0 up to the length of the alphabet minus 1 (imagine an index starting from 0). |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| encrypted_txt | STRING | — |