NB. the playfair cipher with AlliedEnvy: http://codegolf.stackexchange.com/a/23320/5138
NB. 167 char including trailing newline at time of writing
p=:4 :0
a=.u:65+9-.~i.26
,_2(5|,:~@|.@(=/)+$$,A.~5*1-0{=/)&.(5 5#:(~.n x,a)&i.)\(,'X'#~2|#)(({.,'X',}.)~1+2*1{&I._2{.\2=/\]) ::]^:_(n=.a(e.~#])'JI'charsub toupper)y
)
NB. usage is easy: 'KEY' p 'PLAINTEXT'
'Stack Overflow' p 'The cat crept into the crypt, crapped, and crept out again.' NB. SIRACARDFMVUICVSMORDZNAKECMZMFBCYNRDFMSVTVKBTMMY
NB. explanation via explosion!
a=.u:65+9-.~i.26 NB. the playfair alphabet: alphabet minus J
i.26 NB. create a list of the numbers 0 through 25
9-.~ NB. remove the number 9
65+ NB. add 65 to everything
a=.u: NB. convert ascii values to characters, assign to a
(n=.a(e.~#])'JI'charsub toupper) NB. flatten to alphabet, filter j out
toupper NB. convert any lowercase letters to uppercase
'JI'charsub NB. replace all J with I
a NB. alphabet from before
(e.~ ) NB. test to see whether each letter is in the alphabet
#] NB. select those letters out of the string
n=. NB. assign this function to n, we'll need it for later
(({.,'X',}.)~1+2*1{&I._2{.\2=/\]) ::]^:_ NB. add in Xs between repeating letters in the same pair
2=/\] NB. between each pair of letters, test for equality
_2{.\ NB. now between each non-overlapping pair, take the first element
NB. this corresponds to equality over each non-overlapping pair,
NB. but correctly handles the case when the string length is odd
&I. NB. convert the list of booleans to a list of indices where it was true
1{ NB. select the first item, if it exists; throws error if empty list
::] NB. catch this error if it occurs, returning the original string
1+2* NB. index * 2 + 1
({.,'X',}.)~ NB. insert an X after the first 1+2*idx characters
^:_ NB. repeat until no resulting change, i.e. until we catch the error
NB. that appears when there's nothing to break up
(,'X'#~2|#) NB. append an X if there are an odd number of characters
2|# NB. take the length of the string, mod 2
'X'#~ NB. take that many (0 or 1) copies of X
, NB. append it to the string
,_2(...)&.(5 5#:(~.n x,a)&i.)\ NB. actually performing the playfair encoding
( n x,a) NB. append the playfair alphabet to the end of the key, then apply n from before
~. NB. take only the unique characters, in order
&i. NB. find the index of each letter from the string in this keytable
5 5#: NB. expand this base 5 into a pair of coordinates, row and column
(...)&.( ) NB. perform this transformation, then (...), then the INVERSE transformation
NB. i.e. convert chars to indices, do (...), then back to chars
_2 \ NB. perform the above on 2-char non-overlapping pairs
, NB. run all of it back into a single-line string
(5|,:~@|.@(=/)+$$,A.~5*1-0{=/) NB. playfair the indices
=/ NB. test whether the rows and/or the columns are equal
0{ NB. take the result for rows
5*1- NB. do some math, making 0 if true, 5 if false
, NB. run the indices into a line
A.~ NB. permute the list of indices by the number at right:
NB. 0 makes no change, and 5 swaps the columns
$$ NB. restore the original shape of the indices
|.@(=/) NB. row/column equality test, but this time reverse the pair
,:~@ NB. laminate this result with itself, so that we have
NB. 0 1 1 0
NB. 0 1 if rows equal, or 1 0 if columns equal,
NB. or all zeroes otherwise
5| + NB. add the two results together and take everything mod 5
NB. tada! this is the encryption half of the playfair cipher
NB. as a bonus, we can also make a parallel decryption predicate which operates inalmost the exact same way:
NB. it would subtract the shifts made for matching rows/columns, and then strip out all the Xs in the result
NB. that are at the end or in between identical letters
pi=:4 :0 :.p NB. playfair inverse
(}.~'X'-@={:)(#~1-'X'&=*0,@,.0,~2=/\_2{.\]),_2(5|,:~@|.@(=/)-~$$,A.~5*1-0{=/)&.(5 5#:(~.(n=.a(e.~#])'JI'charsub toupper)x,a=.u:65+9-.~i.26)&i.)\(,'X'#~2|#)y
)
p=:p f. :.pi NB. :. is used to define inverses for J; f. is used to dereference p for the definition
'Stack Overflow' pi 'SIRACARDFMVUICVSMORDZNAKECMZMFBCYNRDFMSVTVKBTMMY' NB. THECATCREPTINTOTHECRYPTCRAPPEDANDCREPTOUTAGAIN