Playfair encrypts pairs of letters, using a 5x5 grid.
❌ Perfect Decoding
✅ Uppercase letters (A-Z
)
✅ Lowercase letters (a-z
)
❌ Numbers (0-9
)
❌ Symbols (!@#$
)
❌ Emojis (😍🤬👩🏾💻
)
Numbers, Symbols, and Emojis
Numbers, symbols, and emoji are outputted as-is by this cipher.
No J’s
A limitation of encoding using a 5x5 gris, is there are only 25 potential characters. As a result, most implementations of this cipher combine i and j. This results in all j
's being treated as i
's when encoding and decoding.
What is “Perfect Decoding”?
Perfect Decoding is when the decoded text exactly matches the text that was encoded. This cipher does not have perfect decoding, so you’ll need to do some mental decoding.
Based on the current settings for Playfair:
key = private
cipherAlphabet = privatebcdfghklmnoqsuwxyz
Hello World!
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
!@#$
✨🦄✨
Gbhzhs Xnagl!
DCDTBGHOBVHFSOQVMANFPRYYZA
dcdtbghobvhfsoqvmanfpryyzuy
0123456789
!@#$
✨🦄✨
Helxlo World!
ABCDEFGHIIKLMNOPQRSTUVWXYZ
abcdefghiiklmnopqrstuvwxyzx
0123456789
!@#$
✨🦄✨
key
is any lowercase string of your choice, it cannot include duplicated letters or any j
s.
Given a key
, create a new alphabet with that key in front.
For example, with a key of private
you’ll see the cipher alphabet below, in comparison to the standard English alphabet.
The keyed-alphabet (cipherAlphabet
) generated by the cipher is effectively a shuffled alphabet, with the key at the beginning, that’s why the key cannot have duplicate letters.
key = 'private'
// j has been removed from the cipher alphabet
cipherAlphabet = privatebcdfghklmnoqsuwxyz
standardAlphabet = abcdefghijklmnopqrstuvwxyz
As mentioned, think of the keyed cipherAlphabet
as a 5x5 grid:
p r i v a
t e b c d
f g h k l
m n o q s
u w x y z
When encoding and decoding, loop over the given string getting pairs of letters at a time. Follow any of the rules below that apply to the pair before calculating the encoded/decoded character:
j
: Replace it with an i
x
between the lettersx
With those rules hello
would be encrypted as he
lx
lo
and juice
as iu
ic
ex
.
This pre-processing of the string is what causes this cipher to not have perfect decoding!
For each letter in the pair, you’ll need to calculate the coordinates of the letter in the grid.
Using the cipherAlphabet
created, here are example 0-indexed coordinates (x, y):
h = 2,2
e = 1,1
l = 2,4
x = 4,2
The coordinates are calculated with the following formulas:
{
x: Math.floor(letterPosition / 5),
y: letterPosition mod 5
}
The formulas below for encoding and decoding reference x1, y1
and x2, y2
.
x1
and y1
are the coordinates for the first character.
x2
and y2
map to the second character coordinates.
For each pair check which formula they match:
If the letters are on the same row of the grid (x1 == x2
)
encodedCharacterIndex1 = (x1 * 5) + ((y1 + 1) mod 5)
encodedCharacterIndex2 = (x2 * 5) + ((y2 + 1) mod 5)
If the letters are in the same column of the grid (y1 == y2
)
encodedCharacterIndex1 = ((x1 + 1) mod 5) * 5) + y1
encodedCharacterIndex2 = ((x2 + 1) mod 5) * 5) + y2
Else, the letters are on a diagonal
encodedCharacterIndex1 = (x1 * 5) + y2
encodedCharacterIndex2 = (x2 * 5) + y1
With the calculated encodedCharacterIndex1
and encodedCharacterIndex2
, you can get the new encoded letter at that index in the cipher alphabet.
For each pair check which formula they match:
If the letters are on the same row of the grid (x1 == x2
)
decodedCharacterIndex1 = (x1 * 5) + ((y1 - 1) mod 5)
decodedCharacterIndex2 = (x2 * 5) + ((y2 - 1) mod 5)
If the letters are in the same column of the grid (y1 == y2
)
decodedCharacterIndex1 = ((x1 - 1) mod 5) * 5) + y1
decodedCharacterIndex2 = ((x2 - 1) mod 5) * 5) + y2
Else, the letters are on a diagonal
decodedCharacterIndex1 = (x1 * 5) + y2
decodedCharacterIndex2 = (x2 * 5) + y1
With the calculated decodedCharacterIndex1
and decodedCharacterIndex2
, you can get the decoded letter at that index in the cipher alphabet.
mod
This cipher uses mod 5
which performs the modulo (%) operation. Javascript doesn’t have proper support for mod so this formula is used:
export function mod (a, b) {
return ((a % b) + b) % b
}