Vigenère cipher/Cryptanalysis: Difference between revisions

m
(Updated D entry)
m (→‎{{header|Wren}}: Minor tidy)
 
(45 intermediate revisions by 20 users not shown)
Line 29:
* Use that key to decrypt and output the original plaintext. Maintaining the whitespace from the ciphertext is optional.
* The algorithm doesn't have to be perfect (which may not be possible) but it should work when given enough ciphertext. The example above is fairly long, and should be plenty for any algorithm.
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">-V ascii_uppercase = Array(‘A’..‘Z’)
 
F vigenere_decrypt(target_freqs, input)
V nchars = :ascii_uppercase.len
V ordA = ‘A’.code
V sorted_targets = sorted(target_freqs)
 
F frequency(input)
V result = :ascii_uppercase.map(c -> (c, 0.0))
L(c) input
result[c - @ordA][1]++
R result
 
F correlation(input)
V result = 0.0
V freq = sorted(@frequency(input), key' a -> a[1])
 
L(f) freq
result += f[1] * @sorted_targets[L.index]
R result
 
V cleaned = input.uppercase().filter(c -> c.is_uppercase()).map(c -> c.code)
V best_len = 0
V best_corr = -100.0
 
L(i) 2 .< cleaned.len I/ 20
V pieces = [[Int]()] * i
L(c) cleaned
pieces[L.index % i].append(c)
V corr = -0.5 * i + sum(pieces.map(p -> @correlation(p)))
 
I corr > best_corr
best_len = i
best_corr = corr
 
I best_len == 0
R (‘Text is too short to analyze’, ‘’)
 
V pieces = [[Int]()] * best_len
L(c) cleaned
pieces[L.index % best_len].append(c)
 
V freqs = pieces.map(p -> @frequency(p))
 
V key = ‘’
L(fr_) freqs
V fr = sorted(fr_, key' a -> a[1], reverse' 1B)
V m = 0
V max_corr = 0.0
L(j) 0 .< nchars
V corr = 0.0
V c = ordA + j
L(frc) fr
V d = (frc[0].code - c + nchars) % nchars
corr += frc[1] * target_freqs[d]
 
I corr > max_corr
m = j
max_corr = corr
 
key ‘’= Char(code' m + ordA)
 
V r = (enumerate(cleaned).map((i, c) -> Char(code' (c - @key[i % @best_len].code + @nchars) % @nchars + @ordA)))
R (key, r.join(‘’))
 
V encoded = ‘
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK’
 
V english_frequences = [
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074]
 
V (key, decoded) = vigenere_decrypt(english_frequences, encoded)
print(‘Key: ’key)
print("\nText: "decoded)</syntaxhighlight>
 
{{out}}
<pre>
Key: THECHESHIRECAT
 
Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVE...
</pre>
 
=={{header|Ada}}==
The program is not fully auto, but makes a small number of suggestions for the right key and plaintext.
<langsyntaxhighlight Adalang="ada">with Ada.Text_IO;
 
procedure Vignere_Cryptanalysis is
Line 197 ⟶ 302:
end;
end loop;
end Vignere_Cryptanalysis;</langsyntaxhighlight>
 
=={{header|C}}==
This finds the right key (I think, I didn't try to decode it after getting the key). The program is not fully auto, but by its output, the result is pretty obvious.
<langsyntaxhighlight Clang="c">#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Line 303 ⟶ 408:
 
return 0;
}</langsyntaxhighlight>
 
=={{header|C++}}==
Not guaranteed to give a 100% correct answer, but it works here. Requires C++0x.
 
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <string>
#include <vector>
Line 474 ⟶ 579:
cout << "Key: " << output.second << endl << endl;
cout << "Text: " << output.first << endl;
}</langsyntaxhighlight>
 
=={{header|D}}==
{{trans|C++}}
<langsyntaxhighlight lang="d">import std.stdio, std.algorithm, std.typecons, std.string,
std.array, std.numeric, std.ascii;
 
Line 485 ⟶ 590:
 
static double correlation(in string txt, in double[] sTargets)
/*pure nothrow /*@safe*/ @nogc {
uint[nAlpha] charCounts = 0;
foreach (immutable c; txt)
Line 492 ⟶ 597:
}
 
static frequency(in string txt) pure nothrow @safe {
auto freqs = new Tuple!(char,"c", uint,"d")[nAlpha];
foreach (immutable i, immutable c; std.ascii.uppercase)
Line 502 ⟶ 607:
 
static string[2] decode(in string cleaned, in string key)
pure nothrow @safe {
assert(!key.length > 0empty);
string decoded;
foreach (immutable i, immutable c; cleaned)
Line 512 ⟶ 617:
static size_t findBestLength(in string cleaned,
in double[] sTargets)
/*pure nothrow /*@safe*/ {
size_t bestLength;
double bestCorr = -100.0;
Line 539 ⟶ 644:
 
static string findKey(in string cleaned, in size_t bestLength,
in double[] targetFreqs) /*pure*/ nothrow @safe {
auto pieces = new string[bestLength];
foreach (immutable i, immutable c; cleaned)
Line 571 ⟶ 676:
immutable cleaned = input.toUpper.removechars("^A-Z");
 
//immutable sortedTargets = sorted(targetFreqs).sorted;
immutable sortedTargets = targetFreqs.dup.sort().release.idup;
 
Line 609 ⟶ 714:
immutable key_dec = vigenereDecrypt(englishFrequences, encoded);
writefln("Key: %s\n\nText: %s", key_dec[0], key_dec[1]);
}</langsyntaxhighlight>
{{out|Output (cut)}}
<pre>Key: THECHESHIRECAT
 
Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...</pre>
 
=={{header|Go}}==
{{trans|Kotlin}}
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"strings"
)
 
var encoded =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
 
var freq = [26]float64{
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
}
 
func sum(a []float64) (sum float64) {
for _, f := range a {
sum += f
}
return
}
 
func bestMatch(a []float64) int {
sum := sum(a)
bestFit, bestRotate := 1e100, 0
for rotate := 0; rotate < 26; rotate++ {
fit := 0.0
for i := 0; i < 26; i++ {
d := a[(i+rotate)%26]/sum - freq[i]
fit += d * d / freq[i]
}
if fit < bestFit {
bestFit, bestRotate = fit, rotate
}
}
return bestRotate
}
 
func freqEveryNth(msg []int, key []byte) float64 {
l := len(msg)
interval := len(key)
out := make([]float64, 26)
accu := make([]float64, 26)
for j := 0; j < interval; j++ {
for k := 0; k < 26; k++ {
out[k] = 0.0
}
for i := j; i < l; i += interval {
out[msg[i]]++
}
rot := bestMatch(out)
key[j] = byte(rot + 65)
for i := 0; i < 26; i++ {
accu[i] += out[(i+rot)%26]
}
}
sum := sum(accu)
ret := 0.0
for i := 0; i < 26; i++ {
d := accu[i]/sum - freq[i]
ret += d * d / freq[i]
}
return ret
}
 
func decrypt(text, key string) string {
var sb strings.Builder
ki := 0
for _, c := range text {
if c < 'A' || c > 'Z' {
continue
}
ci := (c - rune(key[ki]) + 26) % 26
sb.WriteRune(ci + 65)
ki = (ki + 1) % len(key)
}
return sb.String()
}
 
func main() {
enc := strings.Replace(encoded, " ", "", -1)
txt := make([]int, len(enc))
for i := 0; i < len(txt); i++ {
txt[i] = int(enc[i] - 'A')
}
bestFit, bestKey := 1e100, ""
fmt.Println(" Fit Length Key")
for j := 1; j <= 26; j++ {
key := make([]byte, j)
fit := freqEveryNth(txt, key)
sKey := string(key)
fmt.Printf("%f %2d %s", fit, j, sKey)
if fit < bestFit {
bestFit, bestKey = fit, sKey
fmt.Print(" <--- best so far")
}
fmt.Println()
}
fmt.Println("\nBest key :", bestKey)
fmt.Printf("\nDecrypted text:\n%s\n", decrypt(enc, bestKey))
}</syntaxhighlight>
 
{{out}}
Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.
<pre>
Fit Length Key
2.984348 1 E <--- best so far
2.483684 2 EC <--- best so far
2.642487 3 TEE
1.976651 4 THEC <--- best so far
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW
 
Best key : THECHESHIRECAT
 
Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|Haskell}}==
<syntaxhighlight lang="haskell">{-# LANGUAGE TupleSections #-}
import Data.List(transpose, nub, sort, maximumBy)
import Data.Ord (comparing)
import Data.Char (ord)
import Data.Map (Map, fromListWith, toList, findWithDefault)
 
average :: Fractional a => [a] -> a
average as = sum as / fromIntegral (length as)
 
-- Create a map from each entry in list to the number of occurrences of
-- that entry in the list.
countEntries :: Ord a => [a] -> Map a Int
countEntries = fromListWith (+) . fmap (,1)
 
-- Break a string up into substrings of n chars.
breakup :: Int -> [a] -> [[a]]
breakup _ [] = []
breakup n as =
let (h, r) = splitAt n as
in h:breakup n r
 
-- Dole out elements of a string over a n element distribution.
distribute :: [a] -> Int -> [[a]]
distribute as n = transpose $ breakup n as
 
-- The probability that members of a pair of characters taken randomly
-- from a given string are equal.
coincidence :: (Ord a, Fractional b) => [a] -> b
coincidence str =
let charCounts = snd <$> toList (countEntries str)
strln = length str
d = fromIntegral $ strln * (strln - 1)
n = fromIntegral $ sum $ fmap (\cc -> cc * (cc-1)) charCounts
in n / d
 
-- Use the average probablity of coincidence for all the members of
-- a distribution to rate the distribution - the higher the better.
-- The correlation increases artificially for smaller
-- pieces/longer keys, so weigh against them a little
rate :: (Ord a, Fractional b) => [[a]] -> b
rate d = average (fmap coincidence d) - fromIntegral (length d) / 3000.0
 
-- Multiply elements of lists together and add up the results.
dot :: Num a => [a] -> [a] -> a
dot v0 v1 = sum $ zipWith (*) v0 v1
 
-- Given two lists of floats, rotate one of them by the number of
-- characters indicated by letter and then 'dot' them together.
rotateAndDot :: Num a => [a] -> [a] -> Char -> a
rotateAndDot v0 v1 letter = dot v0 (drop (ord letter - ord 'A') (cycle v1))
 
-- Find decoding offset that results in best match
-- between actual char frequencies and expected frequencies.
getKeyChar :: RealFrac a => [a] -> String -> Char
getKeyChar expected sample =
let charCounts = countEntries sample
countInSample c = findWithDefault 0 c charCounts
actual = fmap (fromIntegral . countInSample) ['A'..'Z']
in maximumBy (comparing $ rotateAndDot expected actual) ['A'..'Z']
 
main = do
let cr = filter (/=' ') crypt
-- Assume that if there are less than 20 characters
-- per column, the key's too long to guess
distributions = fmap (distribute cr) [1..length cr `div` 20]
bestDistribution = maximumBy (comparing rate) distributions
key = fmap (getKeyChar englishFrequencies) bestDistribution
alphaSum a b = ['A'..'Z'] !! ((ord b - ord a) `mod` 26)
mapM_ putStrLn ["Key: " ++ key, "Decrypted Text: " ++ zipWith alphaSum (cycle key) cr]
 
englishFrequencies =
[ 0.08167, 0.01492, 0.02782, 0.04253,
0.12702, 0.02228, 0.02015, 0.06094,
0.06966, 0.00153, 0.00772, 0.04025,
0.02406, 0.06749, 0.07507, 0.01929,
0.00095, 0.05987, 0.06327, 0.09056,
0.02758, 0.00978, 0.02360, 0.00150,
0.01974, 0.00074 ]
 
crypt = "\
\MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH\
\VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD\
\ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS\
\FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG\
\ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ\
\ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS\
\JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT\
\LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST\
\MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH\
\QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV\
\RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW\
\TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO\
\SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR\
\ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX\
\BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB\
\BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA\
\FWAML ZZRXJ EKAHV FASMU LVVUT TGK\
\"</syntaxhighlight>
{{out}}
<pre style="font-size:80%">
Key: THECHESHIRECAT
Decrypted Text: THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|J}}==
 
Implementation:
<syntaxhighlight lang=J>NB. https://en.wikipedia.org/wiki/Kasiski_examination
kasiski=: {{
grams=. ({: #"1~1 < ;@{.)|:(#/.~;"0~.) g=. 3 <\ y
deltas=. ;grams (2 -~/\ I.@E.)L:0 enc
{:,{.\:~(#/.~,.~.)1 -.~,+./~ deltas
}}
 
NB. https://en.wikipedia.org/wiki/Letter_frequency
AZ=: 8 u: 65+i.26
lfreq=: 0.01*do{{)n
8.2 1.5 2.8 4.3 13 2.2 2 6.1 7 0.15
0.77 4 2.4 6.7 7.5 1.9 0.095 6 6.3 9.1
2.8 0.98 2.4 0.15 2 0.074
}}-.LF
 
 
caesarkey=: {{
freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
AZ{~(i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
}}
vigenerekey=: {{ caesarkey"1|:(-kasiski y) ]\y }}
 
uncaesar=: {{ 26&|@-&(AZ i.x)&.(AZ&i.) y }}"0 1
unvigenere=: {{ ' '-.~,x uncaesar"0 1&.|:(-#x) ]\y }}</syntaxhighlight>
 
Here, kasiski finds all 3-grams (sequences of three adjacent letters) which appear more than once, finds all of the distances between nearest pairs of these sequences, and then further pairs each of these distances with all other distances, finding the greatest common divisor of those distance pairs. Finally, these LCDs are ordered by how many times they appear and the most frequent LCD is taken as the kasiski result.
 
uncaesar works by finding the frequency of occurrence of each letter of the alphabet (in alphabetical order), and then each of the 26 rotations of that sequence are compared with a text frequency alphabet (obtained from a wikipedia table). The rotation with the least root-mean-square sum of differences is chosen as the correct location, and its index is reported as a letter of the alphabet (0=A, 1=B, etc.)
 
(And, the length provided by kasiski is used to break out the sequences to be analyzed by uncaesar...)
 
Task example:
 
<syntaxhighlight lang=J>enc=: {{)n
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
}}-.LF,' '
 
vigenerekey enc
THECHESHIRECAT
_80]\'THECHESHIRECAT' unvigenere enc
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTANDWYTWITSJWYAH
</syntaxhighlight>
 
As an aside, note that we could go directly from encrypted text to decrypted text, without showing the key. For example, using:
<syntaxhighlight lang=J>decaesar=: {{
freqs=. (<:#/.~AZ,y)%#y=. y ([-.-.) AZ
ndx=. (i. <./)lfreq +/&.:*:@:-"1 (i.26)|."0 1 freqs
26&|@-&ndx&.(AZ&i.) y
}}
devigenere=: {{ ' '-.~,decaesar"1&.|:(-kasiski y) ]\y }}</syntaxhighlight>
 
That said, it's also worth noting that noise issues mean that if this were to be used in practical contexts the approach should instead be to expose more intermediate results, rather than less, with a special focus on the representations of frequency distributions (here, we're always picking the first alternative, but it's vaguely plausible that a different alternative might actually be useful in some cases).
 
=={{header|Java}}==
{{trans|C}}
 
<syntaxhighlight lang="java">public class Vig{
static String encodedMessage =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
final static double freq[] = {
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
};
 
public static void main(String[] args) {
int lenghtOfEncodedMessage = encodedMessage.length();
char[] encoded = new char [lenghtOfEncodedMessage] ;
char[] key = new char [lenghtOfEncodedMessage] ;
 
encodedMessage.getChars(0, lenghtOfEncodedMessage, encoded, 0);
int txt[] = new int[lenghtOfEncodedMessage];
int len = 0, j;
 
double fit, best_fit = 1e100;
for (j = 0; j < lenghtOfEncodedMessage; j++)
if (Character.isUpperCase(encoded[j]))
txt[len++] = encoded[j] - 'A';
for (j = 1; j < 30; j++) {
fit = freq_every_nth(txt, len, j, key);
System.out.printf("%f, key length: %2d ", fit, j);
System.out.print(key);
if (fit < best_fit) {
best_fit = fit;
System.out.print(" <--- best so far");
}
System.out.print("\n");
 
}
}
 
 
static String decrypt(String text, final String key) {
String res = "";
text = text.toUpperCase();
for (int i = 0, j = 0; i < text.length(); i++) {
char c = text.charAt(i);
if (c < 'A' || c > 'Z') continue;
res += (char)((c - key.charAt(j) + 26) % 26 + 'A');
j = ++j % key.length();
}
return res;
}
 
static int best_match(final double []a, final double []b) {
double sum = 0, fit, d, best_fit = 1e100;
int i, rotate, best_rotate = 0;
for (i = 0; i < 26; i++)
sum += a[i];
for (rotate = 0; rotate < 26; rotate++) {
fit = 0;
for (i = 0; i < 26; i++) {
d = a[(i + rotate) % 26] / sum - b[i];
fit += d * d / b[i];
}
if (fit < best_fit) {
best_fit = fit;
best_rotate = rotate;
}
}
return best_rotate;
}
static double freq_every_nth(final int []msg, int len, int interval, char[] key) {
double sum, d, ret;
double [] accu = new double [26];
double [] out = new double [26];
int i, j, rot;
for (j = 0; j < interval; j++) {
for (i = 0; i < 26; i++)
out[i] = 0;
for (i = j; i < len; i += interval)
out[msg[i]]++;
rot = best_match(out, freq);
try{
key[j] = (char)(rot + 'A');
} catch (Exception e) {
System.out.print(e.getMessage());
}
for (i = 0; i < 26; i++)
accu[i] += out[(i + rot) % 26];
}
for (i = 0, sum = 0; i < 26; i++)
sum += accu[i];
for (i = 0, ret = 0; i < 26; i++) {
d = accu[i] / sum - freq[i];
ret += d * d / freq[i];
}
key[interval] = '\0';
return ret;
}
}
</syntaxhighlight>
 
=={{header|Julia}}==
 
<syntaxhighlight lang="julia"># ciphertext block {{{1
const ciphertext = filter(isalpha, """
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
""")
# }}}
 
# character frequencies {{{1
const letters = Dict{Char, Float32}(
'E' => 12.702,
'T' => 9.056,
'A' => 8.167,
'O' => 7.507,
'I' => 6.966,
'N' => 6.749,
'S' => 6.327,
'H' => 6.094,
'R' => 5.987,
'D' => 4.253,
'L' => 4.025,
'C' => 2.782,
'U' => 2.758,
'M' => 2.406,
'W' => 2.361,
'F' => 2.228,
'G' => 2.015,
'Y' => 1.974,
'P' => 1.929,
'B' => 1.492,
'V' => 0.978,
'K' => 0.772,
'J' => 0.153,
'X' => 0.150,
'Q' => 0.095,
'Z' => 0.074)
const digraphs = Dict{AbstractString, Float32}(
"TH" => 15.2,
"HE" => 12.8,
"IN" => 9.4,
"ER" => 9.4,
"AN" => 8.2,
"RE" => 6.8,
"ND" => 6.3,
"AT" => 5.9,
"ON" => 5.7,
"NT" => 5.6,
"HA" => 5.6,
"ES" => 5.6,
"ST" => 5.5,
"EN" => 5.5,
"ED" => 5.3,
"TO" => 5.2,
"IT" => 5.0,
"OU" => 5.0,
"EA" => 4.7,
"HI" => 4.6,
"IS" => 4.6,
"OR" => 4.3,
"TI" => 3.4,
"AS" => 3.3,
"TE" => 2.7,
"ET" => 1.9,
"NG" => 1.8,
"OF" => 1.6,
"AL" => 0.9,
"DE" => 0.9,
"SE" => 0.8,
"LE" => 0.8,
"SA" => 0.6,
"SI" => 0.5,
"AR" => 0.4,
"VE" => 0.4,
"RA" => 0.4,
"LD" => 0.2,
"UR" => 0.2)
const trigraphs = Dict{AbstractString, Float32}(
"THE" => 18.1,
"AND" => 7.3,
"ING" => 7.2,
"ION" => 4.2,
"ENT" => 4.2,
"HER" => 3.6,
"FOR" => 3.4,
"THA" => 3.3,
"NTH" => 3.3,
"INT" => 3.2,
"TIO" => 3.1,
"ERE" => 3.1,
"TER" => 3.0,
"EST" => 2.8,
"ERS" => 2.8,
"HAT" => 2.6,
"ATI" => 2.6,
"ATE" => 2.5,
"ALL" => 2.5,
"VER" => 2.4,
"HIS" => 2.4,
"HES" => 2.4,
"ETH" => 2.4,
"OFT" => 2.2,
"STH" => 2.1,
"RES" => 2.1,
"OTH" => 2.1,
"ITH" => 2.1,
"FTH" => 2.1,
"ONT" => 2.0)
# 1}}}
 
function decrypt(enc::ASCIIString, key::ASCIIString)
const enclen = length(enc)
const keylen = length(key)
 
if keylen < enclen
key = (key^(div(enclen - keylen, keylen) + 2))[1:enclen]
end
 
msg = Array(Char, enclen)
 
for i=1:enclen
msg[i] = Char((Int(enc[i]) - Int(key[i]) + 26) % 26 + 65)
end
 
msg::Array{Char, 1}
end
 
function cryptanalyze(enc::ASCIIString; maxkeylen::Integer = 20)
const enclen = length(enc)
maxkey = ""
maxdec = ""
maxscore = 0.0
 
for keylen=1:maxkeylen
key = Array(Char, keylen)
idx = filter(x -> x % keylen == 0, 1:enclen) - keylen + 1
 
for i=1:keylen
maxsubscore = 0.0
 
for j='A':'Z'
subscore = 0.0
 
for k in decrypt(enc[idx], ascii(string(j)))
subscore += get(letters, k, 0.0)
end
 
if subscore > maxsubscore
maxsubscore = subscore
key[i] = j
end
end
 
idx += 1
end
 
key = join(key)
const dec = decrypt(enc, key)
score = 0.0
 
for i in dec
score += get(letters, i, 0.0)
end
 
for i=1:enclen - 2
const digraph = string(dec[i], dec[i + 1])
const trigraph = string(dec[i], dec[i + 1], dec[i + 2])
 
if haskey(digraphs, digraph)
score += 2 * get(digraphs, digraph, 0.0)
end
 
if haskey(trigraphs, trigraph)
score += 3 * get(trigraphs, trigraph, 0.0)
end
end
 
if score > maxscore
maxscore = score
maxkey = key
maxdec = dec
end
end
(maxkey, join(maxdec))::Tuple{ASCIIString, ASCIIString}
end
 
key, dec = cryptanalyze(ciphertext)
println("key: ", key, "\n\n", dec)
 
# post-compilation profiling run
gc()
t = @elapsed cryptanalyze(ciphertext)
println("\nelapsed time: ", t, " seconds")</syntaxhighlight>
 
{{out}}
 
<pre>key: THECHESHIRECAT
 
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHY...
 
elapsed time: 0.042894211 seconds</pre>
 
=={{header|Kotlin}}==
{{trans|C}}
This is a reasonably faithful translation of the C entry though I've restricted the key lengths examined to 26 to automatically produce the correct key and hence decrypted text. This is because the C entry examines key lengths up to 29 and a value of 28 gives a slightly better fit even though the key produced (THECHESCIRECATTHECHESHIRECAT) and resulting text don't make as much sense and so would be rejected if one were examining the candidate keys manually.
<syntaxhighlight lang="scala">// version 1.1.3
 
val encoded =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
 
val freq = doubleArrayOf(
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
)
 
fun bestMatch(a: DoubleArray): Int {
val sum = a.sum()
var bestFit = 1e100
var bestRotate = 0
for (rotate in 0..25) {
var fit = 0.0
for (i in 0..25) {
val d = a[(i + rotate) % 26] / sum - freq[i]
fit += d * d / freq[i]
}
if (fit < bestFit) {
bestFit = fit
bestRotate = rotate
}
}
return bestRotate
}
 
fun freqEveryNth(msg: IntArray, key: CharArray): Double {
val len = msg.size
val interval = key.size
val out = DoubleArray(26)
val accu = DoubleArray(26)
for (j in 0 until interval) {
out.fill(0.0)
for (i in j until len step interval) out[msg[i]]++
val rot = bestMatch(out)
key[j] = (rot + 65).toChar()
for (i in 0..25) accu[i] += out[(i + rot) % 26]
}
val sum = accu.sum()
var ret = 0.0
for (i in 0..25) {
val d = accu[i] / sum - freq[i]
ret += d * d / freq[i]
}
return ret
}
 
fun decrypt(text: String, key: String): String {
val sb = StringBuilder()
var ki = 0
for (c in text) {
if (c !in 'A'..'Z') continue
val ci = (c.toInt() - key[ki].toInt() + 26) % 26
sb.append((ci + 65).toChar())
ki = (ki + 1) % key.length
}
return sb.toString()
}
 
fun main(args: Array<String>) {
val enc = encoded.replace(" ", "")
val txt = IntArray(enc.length) { enc[it] - 'A' }
var bestFit = 1e100
var bestKey = ""
val f = "%f %2d %s"
println(" Fit Length Key")
for (j in 1..26) {
val key = CharArray(j)
val fit = freqEveryNth(txt, key)
val sKey = key.joinToString("")
print(f.format(fit, j, sKey))
if (fit < bestFit) {
bestFit = fit
bestKey = sKey
print(" <--- best so far")
}
println()
}
println()
println("Best key : $bestKey")
println("\nDecrypted text:\n${decrypt(enc, bestKey)}")
}</syntaxhighlight>
 
{{out}}
<pre>
Fit Length Key
2.984348 1 E <--- best so far
2.483684 2 EC <--- best so far
2.642487 3 TEE
1.976651 4 THEC <--- best so far
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW
 
Best key : THECHESHIRECAT
 
Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|Nim}}==
{{trans|Julia}}
{{trans|Phix}}
This is a translation of Julia algorithm with some ideas from Phix translation.
<syntaxhighlight lang="nim">import sequtils, strutils, sugar, tables, times
 
const
 
CipherText = """MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK""".splitWhitespace.join()
 
FreqLetters = {'E': 12.702, 'T': 9.056, 'A': 8.167, 'O': 7.507,
'I': 6.966, 'N': 6.749, 'S': 6.327, 'H': 6.094,
'R': 5.987, 'D': 4.253, 'L': 4.025, 'C': 2.782,
'U': 2.758, 'M': 2.406, 'W': 2.361, 'F': 2.228,
'G': 2.015, 'Y': 1.974, 'P': 1.929, 'B': 1.492,
'V': 0.978, 'K': 0.772, 'J': 0.153, 'X': 0.150,
'Q': 0.095, 'Z': 0.074}.toTable
 
FreqDigraphs = {"TH": 15.2, "HE": 12.8, "IN": 9.4, "ER": 9.4,
"AN": 8.2, "RE": 6.8, "ND": 6.3, "AT": 5.9,
"ON": 5.7, "NT": 5.6, "HA": 5.6, "ES": 5.6,
"ST": 5.5, "EN": 5.5, "ED": 5.3, "TO": 5.2,
"IT": 5.0, "OU": 5.0, "EA": 4.7, "HI": 4.6,
"IS": 4.6, "OR": 4.3, "TI": 3.4, "AS": 3.3,
"TE": 2.7, "ET": 1.9, "NG": 1.8, "OF": 1.6,
"AL": 0.9, "DE": 0.9, "SE": 0.8, "LE": 0.8,
"SA": 0.6, "SI": 0.5, "AR": 0.4, "VE": 0.4,
"RA": 0.4, "LD": 0.2, "UR": 0.2}.toTable
 
FreqTrigraphs = {"THE": 18.1, "AND": 7.3, "ING": 7.2, "ION": 4.2,
"ENT": 4.2, "HER": 3.6, "FOR": 3.4, "THA": 3.3,
"NTH": 3.3, "INT": 3.2, "TIO": 3.1, "ERE": 3.1,
"TER": 3.0, "EST": 2.8, "ERS": 2.8, "HAT": 2.6,
"ATI": 2.6, "ATE": 2.5, "ALL": 2.5, "VER": 2.4,
"HIS": 2.4, "HES": 2.4, "ETH": 2.4, "OFT": 2.2,
"STH": 2.1, "RES": 2.1, "OTH": 2.1, "ITH": 2.1,
"FTH": 2.1, "ONT": 2.0}.toTable
 
func decrypt(enc, key: string): string =
let encLen = enc.len
let keyLen = key.len
result.setLen(encLen)
var k = 0
for i in 0..<encLen:
result[i] = chr((ord(enc[i]) - ord(key[k]) + 26) mod 26 + ord('A'))
k = (k + 1) mod keyLen
 
func cryptanalyze(enc: string; maxKeyLen = 20): tuple[maxKey, maxDec: string] =
let encLen = enc.len
var maxScore = 0.0
 
for keyLen in 1..maxKeyLen:
var key = newString(keyLen)
var idx = collect(newSeq):
for i in 1..encLen:
if i mod keyLen == 0:
i - keyLen
 
for i in 0..<keyLen:
var maxSubscore = 0.0
for j in 'A'..'Z':
var subscore = 0.0
let encidx = idx.mapIt(enc[it]).join()
for k in decrypt(encidx, $j):
subscore += FreqLetters[k]
if subscore > maxSubscore:
maxSubscore = subscore
key[i] = j
for item in idx.mitems: inc item
 
let dec = decrypt(enc, key)
var score = 0.0
for i in dec:
score += FreqLetters[i]
 
for i in 0..(encLen - 3):
let digraph = dec[i..(i+1)]
let trigraph = dec[i..(i+2)]
score += 2 * FreqDigraphs.getOrDefault(digraph)
score += 3 * FreqTrigraphs.getOrDefault(trigraph)
 
if score > maxScore:
maxScore = score
result.maxKey = key
result.maxDec = dec
 
let t0 = cpuTime()
let (key, dec) = CipherText.cryptanalyze()
echo "key: ", key, '\n'
echo dec, '\n'
echo "Elapsed time: ", (cpuTime() - t0).formatFloat(ffDecimal, precision = 3), " s"</syntaxhighlight>
 
{{out}}
<pre>key: THECHESHIRECAT
 
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
 
Elapsed time: 0.041 s</pre>
 
=={{header|OCaml}}==
Original version by [http://rosettacode.org/wiki/User:Vanyamil User:Vanyamil].
 
Uses the Vigenere decrypt function from the Vigenere task solution (not included in the code below).
{{works with|OCaml|above 4.05}}
<syntaxhighlight lang="ocaml">
(* Task : Vigenere cipher/Cryptanalysis *)
 
(*
Given some text you suspect has been encrypted
with a Vigenère cipher, extract the key and plaintext.
Uses correlation factors similar to other solutions.
(originally tried Friedman test, didn't produce good result)
Coded in a way that allows non-english (by passing frequencies).
*)
 
(*** Helpers ***)
 
(* Implementation of Float.round to avoid v4.08 *)
let round (x : float) : float =
let rem = mod_float x 1. in
if rem >= 0.5
then ceil x
else floor x
 
(* A function that updates array element at a position *)
let array_update (arr : 'a array) (idx : int) (update : 'a -> 'a) : unit =
let curr = Array.get arr idx in
Array.set arr idx (update curr)
 
(*** Actual task at hand ***)
 
(* the n'th element of array is how often the n'th letter was found *)
let observe_coincidences ?(step : int = 1) ?(offset : int = 0) (text : string) : int array =
let arr = Array.make 26 0 in
let a_code = Char.code 'A' in
String.iteri (fun idx c -> if idx mod step = offset then array_update arr (Char.code c - a_code) succ) text;
arr
 
(* Obtain correlation factor for the observed coincidences *)
let correlation_factor ?(sort : bool = true) (coincidences : int array) (freqs : float list) : float =
let clist = Array.to_list coincidences in
let clist = (if sort then List.sort compare clist else clist) in
List.fold_left2 (fun acc c f -> acc +. (float_of_int c *. f)) 0. clist freqs
 
(* Translation of the test used in other Rosetta Code solutions *)
let shifted_coincidences_test (freqs : float list) (text : string) : int =
let sorted_freqs = List.sort compare freqs in
let bestCorr = -100. in
let max_keylen = String.length text / 20 in
let rec helper idx (cur_len, cur_corr) (best_len, best_corr) =
if cur_len = max_keylen then (* Finished testing everything *)
best_len
else if idx = cur_len then (* Finished testing this key length *)
let (best_len, best_corr) = if cur_corr > best_corr then (cur_len, cur_corr) else (best_len, best_corr) in
helper 0 (cur_len + 1, ~-.0.5 *. float_of_int (cur_len + 1)) (best_len, best_corr)
else
let coincidences = observe_coincidences ~step:cur_len ~offset:idx text in
let factor = correlation_factor coincidences sorted_freqs in
helper (succ idx) (cur_len, cur_corr +. factor) (best_len, best_corr)
in
helper 0 (2, ~-.1.) (1, ~-.100.)
 
(* Returns the most likely shift value for this set *)
let break_caesar ?(step : int = 1) ?(offset : int = 0) (text : string) (freqs : float list) : int =
let c_arr = observe_coincidences ~step ~offset text in
let rec helper l curShift (maxShift, maxCorr) =
if curShift = 26
then maxShift
else
let corr = correlation_factor ~sort:false c_arr l in
let l' = List.tl l @ [List.hd l] in
if corr > maxCorr
then helper l' (curShift + 1) (curShift, corr)
else helper l' (curShift + 1) (maxShift, maxCorr)
in
helper freqs 0 (-1, -100.)
 
let break (keylen : int) (text : string) (freqs : float list) : key =
let rec getCaesars idx acc =
if idx >= keylen then acc else
let shift = break_caesar ~step:keylen ~offset:idx text freqs in
let new_code = if shift = 0 then Char.code 'A' else Char.code 'Z' + 1 - shift in
getCaesars (succ idx) (acc ^ Char.(new_code |> chr |> escaped))
in
getCaesars 0 ""
 
let cryptanalyze (freqs : float list) (text : string) : key * string =
let text = ascii_upper_letters_only text in
let keylen = shifted_coincidences_test freqs text in
let key = break keylen text freqs in
let pt = decrypt key text in
(key, pt)
 
(*** Output ***)
 
let _ =
let long_text = "\
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH \
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD \
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS \
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG \
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ \
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS \
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT \
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST \
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH \
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV \
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW \
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO \
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR \
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX \
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB \
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA \
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
in
let english_freqs = [
0.08167; 0.01492; 0.02782; 0.04253; 0.12702; 0.02228; 0.02015;
0.06094; 0.06966; 0.00153; 0.00772; 0.04025; 0.02406; 0.06749;
0.07507; 0.01929; 0.00095; 0.05987; 0.06327; 0.09056; 0.02758;
0.00978; 0.02360; 0.00150; 0.01974; 0.00074
]
in
let (key, pt) = cryptanalyze english_freqs long_text in
Printf.printf "Key: %s\n\nText: %s" key pt
;;
</syntaxhighlight>
{{out}}
<pre>
Key: THECHESHIRECAT
 
Text: THISWASTHEPOEMTHATALICEREADJABBERWOC...
</pre>
 
=={{header|Perl}}==
<syntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
 
# from Wikipedia
my %English_letter_freq = (
E => 12.70, L => 4.03, Y => 1.97, P => 1.93, T => 9.06, A => 8.17, O => 7.51, I => 6.97, N => 6.75,
S => 6.33, H => 6.09, R => 5.99, D => 4.25, C => 2.78, U => 2.76, M => 2.41, W => 2.36, F => 2.23,
G => 2.02, B => 1.29, V => 0.98, K => 0.77, J => 0.15, X => 0.15, Q => 0.10, Z => 0.07
);
my @alphabet = sort keys %English_letter_freq;
my $max_key_lengths = 5; # number of keylengths to try
 
sub myguess {
my ($text) = (@_);
my ($seqtext, @spacing, @factors, @sortedfactors, $pos, %freq, %Keys);
 
# Kasiski examination
$seqtext = $text;
while ($seqtext =~ /(...).*\1/) {
$seqtext = substr($seqtext, 1+index($seqtext, $1));
push @spacing, 1 + index($seqtext, $1);
}
 
for my $j (@spacing) {
push @factors, grep { $j % $_ == 0 } 2..$j;
}
$freq{$_}++ for @factors;
@sortedfactors = grep { $_ >= 4 } sort { $freq{$b} <=> $freq{$a} } keys %freq; # discard very short keys
 
for my $keylen ( @sortedfactors[0..$max_key_lengths-1] ) {
my $keyguess = '';
for (my $i = 0; $i < $keylen; $i++) {
my($mykey, %chi_values, $bestguess);
for (my $j = 0; $j < length($text); $j += $keylen) {
$mykey .= substr($text, ($j+$i) % length($text), 1);
}
 
for my $subkey (@alphabet) {
my $decrypted = mycrypt($mykey, $subkey);
my $length = length($decrypted);
for my $char (@alphabet) {
my $expected = $English_letter_freq{$char} * $length / 100;
my $observed;
++$observed while $decrypted =~ /$char/g;
$chi_values{$subkey} += ($observed - $expected)**2 / $expected if $observed;
}
}
 
$Keys{$keylen}{score} = $chi_values{'A'};
for my $sk (sort keys %chi_values) {
if ($chi_values{$sk} <= $Keys{$keylen}{score}) {
$bestguess = $sk;
$Keys{$keylen}{score} = $chi_values{$sk};
}
}
$keyguess .= $bestguess;
}
$Keys{$keylen}{key} = $keyguess;
}
map { $Keys{$_}{key} } sort { $Keys{$a}{score} <=> $Keys{$b}{score}} keys %Keys;
}
 
sub mycrypt {
my ($text, $key) = @_;
my ($new_text, %values_numbers);
 
my $keylen = length($key);
@values_numbers{@alphabet} = 0..25;
my %values_letters = reverse %values_numbers;
 
for (my $i = 0; $i < length($text); $i++) {
my $val = -1 * $values_numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
+ $values_numbers{substr($text, $i, 1)};
$new_text .= $values_letters{ $val % 26 };
}
return $new_text;
}
 
my $cipher_text = <<~'EOD';
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD
 
my $text = uc($cipher_text) =~ s/[^@{[join '', @alphabet]}]//gr;
 
for my $key ( myguess($text) ) {
say "Key $key\n" .
"Key length " . length($key) . "\n" .
"Plaintext " . substr(mycrypt($text, $key), 0, 80) . "...\n";
}</syntaxhighlight>
 
{{out}}
<pre>Key THECHESHIRECAT
Key length 14
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...
 
Key THECHESCIRECATTHECHESHIRECAT
Key length 28
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...
 
Key TJGGAHET
Key length 8
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...
 
Key THECSAS
Key length 7
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...
 
Key THEC
Key length 4
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre>
 
=={{header|Phix}}==
{{trans|Julia}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Cryptanalysis.exw
--</span>
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">t0</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">time</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">ciphertext</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">substitute_all</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"""
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK"""</span><span style="color: #0000FF;">,{</span><span style="color: #008000;">" "</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"\n"</span><span style="color: #0000FF;">},{</span><span style="color: #008000;">""</span><span style="color: #0000FF;">,</span><span style="color: #008000;">""</span><span style="color: #0000FF;">})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">letters</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
<span style="color: #0000FF;">{{</span><span style="color: #008000;">'E'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12.702</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'T'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.056</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'A'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8.167</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'O'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.507</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'I'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.966</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'N'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.749</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'S'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.327</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'H'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.094</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'R'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.987</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'D'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.253</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'L'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.025</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'C'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.782</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'U'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.758</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'M'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.406</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'W'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.361</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'F'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.228</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'G'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.015</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Y'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.974</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'P'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.929</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'B'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.492</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'V'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.978</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'K'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.772</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'J'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.153</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'X'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.150</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Q'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.095</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">'Z'</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.074</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">digraphs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
<span style="color: #0000FF;">{{</span><span style="color: #008000;">"TH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">15.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">12.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">9.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">8.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ND"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">6.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ON"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ST"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EN"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ED"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TO"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OU"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">5.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"IS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.7</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ET"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NG"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OF"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AL"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"DE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.9</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"LE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"SI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"VE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"LD"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"UR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">0.2</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">trigraphs</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">new_dict</span><span style="color: #0000FF;">(</span>
<span style="color: #0000FF;">{{</span><span style="color: #008000;">"THE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">18.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"AND"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ING"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">7.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ION"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ENT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">4.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"FOR"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"THA"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"NTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.3</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"INT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TIO"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ERE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"TER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">3.0</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"EST"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ERS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.8</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HAT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ATI"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.6</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ATE"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ALL"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.5</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"VER"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HIS"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"HES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ETH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.4</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OFT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.2</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"STH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"RES"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"OTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ITH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"FTH"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.1</span><span style="color: #0000FF;">},</span>
<span style="color: #0000FF;">{</span><span style="color: #008000;">"ONT"</span><span style="color: #0000FF;">,</span><span style="color: #000000;">2.0</span><span style="color: #0000FF;">}})</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">string</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">keylen</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">key</span><span style="color: #0000FF;">),</span> <span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">1</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">msg</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">))</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">msg</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]-</span><span style="color: #000000;">key</span><span style="color: #0000FF;">[</span><span style="color: #000000;">k</span><span style="color: #0000FF;">]+</span><span style="color: #000000;">26</span><span style="color: #0000FF;">,</span><span style="color: #000000;">26</span><span style="color: #0000FF;">)+</span><span style="color: #008000;">'A'</span>
<span style="color: #000000;">k</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">k</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">msg</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">cryptanalyze</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">maxkeylen</span><span style="color: #0000FF;">=</span><span style="color: #000000;">20</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">enclen</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">maxkey</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">maxdec</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span><span style="color: #0000FF;">,</span>
<span style="color: #000000;">k1</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">" "</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">maxscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">keylen</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">maxkeylen</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">key</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #008000;">' '</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">enclen</span> <span style="color: #008080;">do</span>
<span style="color: #008080;">if</span> <span style="color: #7060A8;">mod</span><span style="color: #0000FF;">(</span><span style="color: #000000;">i</span><span style="color: #0000FF;">,</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">)=</span><span style="color: #000000;">0</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">keylen</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">keylen</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">maxsubscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">j</span><span style="color: #0000FF;">=</span><span style="color: #008000;">'A'</span> <span style="color: #008080;">to</span> <span style="color: #008000;">'Z'</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">subscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #000000;">k1</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">encidx</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">""</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">ii</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">encidx</span> <span style="color: #0000FF;">&=</span> <span style="color: #000000;">enc</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">[</span><span style="color: #000000;">ii</span><span style="color: #0000FF;">]]</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">encidx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">k1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">di</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">subscore</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">di</span><span style="color: #0000FF;">],</span><span style="color: #000000;">letters</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">subscore</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">maxsubscore</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">maxsubscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">subscore</span>
<span style="color: #000000;">key</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">j</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">sq_add</span><span style="color: #0000FF;">(</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">,</span><span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">dec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">decrypt</span><span style="color: #0000FF;">(</span><span style="color: #000000;">enc</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">key</span><span style="color: #0000FF;">)</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">score</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">0.0</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span><span style="color: #000000;">letters</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">enclen</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">2</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">digraph</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">+</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span>
<span style="color: #004080;">string</span> <span style="color: #000000;">trigraph</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">2</span><span style="color: #0000FF;">]</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">2</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">digraph</span><span style="color: #0000FF;">,</span><span style="color: #000000;">digraphs</span><span style="color: #0000FF;">)</span>
<span style="color: #000000;">score</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">3</span> <span style="color: #0000FF;">*</span> <span style="color: #7060A8;">getd</span><span style="color: #0000FF;">(</span><span style="color: #000000;">trigraph</span><span style="color: #0000FF;">,</span><span style="color: #000000;">trigraphs</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">if</span> <span style="color: #000000;">score</span> <span style="color: #0000FF;">></span> <span style="color: #000000;">maxscore</span> <span style="color: #008080;">then</span>
<span style="color: #000000;">maxscore</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">score</span>
<span style="color: #000000;">maxkey</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">key</span>
<span style="color: #000000;">maxdec</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">dec</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">maxkey</span><span style="color: #0000FF;">,</span><span style="color: #000000;">maxdec</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">fold</span><span style="color: #0000FF;">(</span><span style="color: #004080;">string</span> <span style="color: #000000;">s</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">integer</span> <span style="color: #000000;">w</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">w</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">s</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">by</span> <span style="color: #000000;">w</span> <span style="color: #008080;">do</span>
<span style="color: #000000;">s</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">..</span><span style="color: #000000;">i</span><span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">=</span> <span style="color: #008000;">"\n"</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">s</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #004080;">string</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">dec</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">cryptanalyze</span><span style="color: #0000FF;">(</span><span style="color: #000000;">ciphertext</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"key: %s\n\n%s\n\n"</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">key</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">fold</span><span style="color: #0000FF;">(</span><span style="color: #000000;">dec</span><span style="color: #0000FF;">,</span><span style="color: #000000;">80</span><span style="color: #0000FF;">)})</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"elapsed time: %3.2f seconds"</span><span style="color: #0000FF;">,{</span><span style="color: #7060A8;">time</span><span style="color: #0000FF;">()-</span><span style="color: #000000;">t0</span><span style="color: #0000FF;">})</span>
<span style="color: #0000FF;">{}</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">wait_key</span><span style="color: #0000FF;">()</span>
<!--</syntaxhighlight>-->
{{Out}}
<pre>
key: THECHESHIRECAT
 
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIM
BLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKM
YSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDER
SNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUM
TUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESO
FFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGH
ANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPH
INGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOH
CALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEAL
LMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHAD
FINISHEDITBUTITSRATHERHARDTOUNDERSTAND
 
elapsed time: 0.42 seconds
</pre>
 
=={{header|Python}}==
{{trans|D}}
<langsyntaxhighlight lang="python">from string import uppercase
from operator import itemgetter
 
Line 722 ⟶ 2,269:
print "\nText:", decoded
 
main()</langsyntaxhighlight>
 
=={{header|Racket}}==
Line 729 ⟶ 2,276:
This is a simple method that just tries to find a key of any length that minimizes the difference from the expected English character distributions.
 
<syntaxhighlight lang="racket">
<lang Racket>
#lang at-exp racket
 
Line 801 ⟶ 2,348:
(display (integer->char (+ first-char (decode-num n))))))
(newline)
</syntaxhighlight>
</lang>
 
Output:
Line 814 ⟶ 2,361:
This is an attempt at following the [http://en.wikipedia.org/wiki/Index_of_coincidence#Example Wikipedia] description. However, it performs just as well as the simple version. Most likely because I know almost nothing about cryptography...
 
<syntaxhighlight lang="racket">
<lang Racket>
#lang at-exp racket
 
Line 920 ⟶ 2,467:
(display (integer->char (+ first-char (decode-num n))))))
(newline)
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
{{trans|Perl}}
<syntaxhighlight lang="raku" line># from Wikipedia
constant %English-letter-freq = (
E => 12.70, L => 4.03, Y => 1.97, P => 1.93, T => 9.06, A => 8.17, O => 7.51, I => 6.97, N => 6.75,
S => 6.33, H => 6.09, R => 5.99, D => 4.25, C => 2.78, U => 2.76, M => 2.41, W => 2.36, F => 2.23,
G => 2.02, B => 1.29, V => 0.98, K => 0.77, J => 0.15, X => 0.15, Q => 0.10, Z => 0.07
);
constant @alphabet = %English-letter-freq.keys.sort;
constant max_key_lengths = 5; # number of keylengths to try
 
sub myguess ($text) {
my ($seqtext, @spacing, @factors, $pos, %freq, %Keys);
 
# Kasiski examination
$seqtext = $text;
while ($seqtext ~~ /$<sequence>=[...].*$<sequence>/) {
$seqtext = substr($seqtext, 1+index($seqtext, $<sequence>));
push @spacing, 1 + index($seqtext, $<sequence>);
}
for @spacing -> $j {
%freq{$_}++ for grep { $j %% $_ }, 2..$j;
}
 
# discard very short keys, and test only the most likely remaining key lengths
(%freq.keys.grep(* > 3).sort({%freq{$_}}).tail(max_key_lengths)).race(:1batch).map: -> $keylen {
my $key-guess = '';
loop (my $i = 0; $i < $keylen; $i++) {
my ($mykey, %chi-square, $best-guess);
loop (my $j = 0; $j < $text.chars; $j += $keylen) {
$mykey ~= substr($text, ($j+$i) % $text.chars, 1);
}
 
for @alphabet -> $subkey {
my $decrypted = mycrypt($mykey, $subkey);
my $length = $decrypted.chars;
for @alphabet -> $char {
my $expected = %English-letter-freq{$char} * $length / 100;
my $observed = $decrypted.comb.grep(* eq $char).elems;
%chi-square{$subkey} += ($observed - $expected)² / $expected if $observed;
}
}
%Keys{$keylen}{'score'} = %chi-square{@alphabet[0]};
for %chi-square.keys.sort -> $sk {
if (%chi-square{$sk} <= %Keys{$keylen}{'score'}) {
$best-guess = $sk;
%Keys{$keylen}{'score'} = %chi-square{$sk};
}
}
$key-guess ~= $best-guess;
}
%Keys{$keylen}{'key'} = $key-guess;
}
%Keys.keys.sort({ %Keys{$_}{'score'} }).map:{ %Keys{$_}{'key'} };
}
 
sub mycrypt ($text, $key) {
constant %values-numbers = @alphabet Z=> ^@alphabet;
constant %values-letters = %values-numbers.invert;
 
my ($new-text);
my $keylen = $key.chars;
loop (my $i = 0; $i < $text.chars; $i++) {
my $val = -1 * %values-numbers{substr( $key, $i%$keylen, 1)} # negative shift for decode
+ %values-numbers{substr($text, $i, 1)};
$new-text ~= %values-letters{ $val % @alphabet };
}
return $new-text;
}
 
my $cipher-text = .uc.trans(@alphabet => '', :c) given q:to/EOD/;
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK
EOD
 
for myguess($cipher-text) -> $key {
say "Key $key\n" ~
"Key length {$key.chars}\n" ~
"Plaintext {substr(mycrypt($cipher-text, $key), 0, 80)}...\n";
}</syntaxhighlight>
{{out}}
<pre>Key THECHESHIRECAT
Key length 14
Plaintext THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB...
 
Key THECHESCIRECATTHECHESHIRECAT
Key length 28
Plaintext THISWASYHEPOEMTHATALICEREADJABBERWOHKYTWASBRILLIGANDTHESLITHYTOAESDIDGYREANDGIMB...
 
Key TJGGAHET
Key length 8
Plaintext TFGODXGHWMNKEYIVLMBJACIPPTXWTBBNFRADSITFHCOSMGOTFYPOXCASLGRDFQCJTABEDSNFPTOBYIQZ...
 
Key THECSAS
Key length 7
Plaintext THISLESHIRRYENTHATPPIQFEGKDKABBEGAOQLLVGATBRILAMGOOQVRETLITHNXOJFFFSDHYREACHGWNO...
 
Key THEC
Key length 4
Plaintext THISKXGYWOPOLYIMLODNHCIGPVZAABBEFTCHZITWHEQWTGOKFARSECAJLITHMQCATCDIKSNWPVQFFIQQ...</pre>
 
=={{header|Rust}}==
{{trans|Kotlin}}
Note that the character to/from byte ('''u8''') conversions work here only because the key and cryptogram are composed of ASCII characters only. Indeed, Rust's '''char''' type is a ''Unicode scalar value'', how they are represented is well summarized in the Rust book's [https://doc.rust-lang.org/std/primitive.char.html subchapter on strings].
<syntaxhighlight lang="rust">
use std::iter::FromIterator;
 
const CRYPTOGRAM: &str = "MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
 
const FREQUENCIES: [f32; 26] = [
0.08167, 0.01492, 0.02202, 0.04253, 0.12702, 0.02228, 0.02015, 0.06094, 0.06966, 0.00153,
0.01292, 0.04025, 0.02406, 0.06749, 0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09356,
0.02758, 0.00978, 0.02560, 0.00150, 0.01994, 0.00077,
];
 
fn best_match(a: &[f32]) -> u8 {
let sum: f32 = a.iter().sum();
let mut best_fit = std::f32::MAX;
let mut best_rotate = 0;
for rotate in 0..=25 {
let mut fit = 0.;
for i in 0..=25 {
let char_freq = FREQUENCIES[i];
let idx = (i + rotate as usize) % 26 as usize;
let d = a[idx] / sum - char_freq;
fit += d * d / char_freq;
}
if fit < best_fit {
best_fit = fit;
best_rotate = rotate;
}
}
 
best_rotate
}
 
fn freq_every_nth(msg: &[u8], key: &mut [char]) -> f32 {
let len = msg.len();
let interval = key.len();
let mut accu = [0.; 26];
for j in 0..interval {
let mut out = [0.; 26];
for i in (j..len).step_by(interval) {
let idx = msg[i] as usize;
out[idx] += 1.;
}
let rot = best_match(&out);
key[j] = char::from(rot + b'A');
for i in 0..=25 {
let idx: usize = (i + rot as usize) % 26;
accu[i] += out[idx];
}
}
let sum: f32 = accu.iter().sum();
let mut ret = 0.;
for i in 0..=25 {
let char_freq = FREQUENCIES[i];
let d = accu[i] / sum - char_freq;
ret += d * d / char_freq;
}
ret
}
 
fn decrypt(text: &str, key: &str) -> String {
let key_chars_cycle = key.as_bytes().iter().map(|b| *b as i32).cycle();
let is_ascii_uppercase = |c: &u8| (b'A'..=b'Z').contains(c);
text.as_bytes()
.iter()
.filter(|c| is_ascii_uppercase(c))
.map(|b| *b as i32)
.zip(key_chars_cycle)
.fold(String::new(), |mut acc, (c, key_char)| {
let ci: u8 = ((c - key_char + 26) % 26) as u8;
acc.push(char::from(b'A' + ci));
acc
})
}
fn main() {
let enc = CRYPTOGRAM
.split_ascii_whitespace()
.collect::<Vec<_>>()
.join("");
let cryptogram: Vec<u8> = enc.as_bytes().iter().map(|b| u8::from(b - b'A')).collect();
let mut best_fit = std::f32::MAX;
let mut best_key = String::new();
for j in 1..=26 {
let mut key = vec!['\0'; j];
let fit = freq_every_nth(&cryptogram, &mut key);
let s_key = String::from_iter(key); // 'from_iter' is imported from std::iter::FromIterator;
if fit < best_fit {
best_fit = fit;
best_key = s_key;
}
}
 
println!("best key: {}", &best_key);
println!("\nDecrypted text:\n{}", decrypt(&enc, &best_key));
}
</syntaxhighlight>
{{out}}
<pre>
best key: THECHESHIRECAT
 
Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|Tcl}}==
{{trans|Python}}
<langsyntaxhighlight lang="tcl">package require Tcl 8.6
 
oo::class create VigenereAnalyzer {
Line 1,041 ⟶ 2,827:
return [my GetKeyFromFreqs $freqs]
}
}</langsyntaxhighlight>
Demonstration (that assumes that the Tcl solution to [[Vigenère cipher#Tcl|Vigenère cipher]] task is present):
<langsyntaxhighlight lang="tcl">set encoded "
MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
Line 1,067 ⟶ 2,853:
set decoded [decoder decrypt $encoded]
puts "Key: $key"
puts "Text: $decoded"</langsyntaxhighlight>
 
=={{header|Vedit macro language}}==
Line 1,083 ⟶ 2,869:
If this does not solve some encrypted text, you could increase the number of key combinations to be checked.
 
<langsyntaxhighlight lang="vedit">// (1) Copy text into tmp buffer and remove non-alpha chars.
 
Chdir(PATH_ONLY)
Line 1,399 ⟶ 3,185:
BOL
#37 = Search_Block("|V", Cur_Pos, EOL_Pos, ALL+NOERR)
Return </langsyntaxhighlight>
 
=={{header|V (Vlang)}}==
{{trans|Go}}
<syntaxhighlight lang="v (vlang)">import strings
const encoded =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
const freq = [
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074,
]
fn sum(a []f64) f64 {
mut s := 0.0
for f in a {
s += f
}
return s
}
fn best_match(a []f64) int {
s := sum(a)
mut best_fit, mut best_rotate := 1e100, 0
for rotate in 0..26 {
mut fit := 0.0
for i in 0..26 {
d := a[(i+rotate)%26]/s - freq[i]
fit += d * d / freq[i]
}
if fit < best_fit {
best_fit, best_rotate = fit, rotate
}
}
return best_rotate
}
fn freq_every_nth(msg []int, mut key []u8) f64 {
l := msg.len
interval := key.len
mut out := []f64{len: 26}
mut accu := []f64{len: 26}
for j in 0..interval {
for z in 0..26 {
out[z] = 0.0
}
for i := j; i < l; i += interval {
out[msg[i]]++
}
rot := best_match(out)
key[j] = u8(rot + 65)
for i := 0; i < 26; i++ {
accu[i] += out[(i+rot)%26]
}
}
s := sum(accu)
mut ret := 0.0
for i := 0; i < 26; i++ {
d := accu[i]/s - freq[i]
ret += d * d / freq[i]
}
return ret
}
fn decrypt(text string, key string) string {
mut sb := strings.new_builder(128)
mut ki := 0
for c in text {
if c < 'A'[0] || c > 'Z'[0] {
continue
}
ci := (c - key[ki] + 26) % 26
sb.write_rune(ci + 65)
ki = (ki + 1) % key.len
}
return sb.str()
}
fn main() {
enc := encoded.replace(" ", "")
mut txt := []int{len: enc.len}
for i in 0..txt.len {
txt[i] = int(enc[i] - 'A'[0])
}
mut best_fit, mut best_key := 1e100, ""
println(" Fit Length Key")
for j := 1; j <= 26; j++ {
mut key := []u8{len: j}
fit := freq_every_nth(txt, mut key)
s_key := key.bytestr()
print("${fit:.6} ${j:2} $s_key")
if fit < best_fit {
best_fit, best_key = fit, s_key
print(" <--- best so far")
}
println('')
}
println("\nBest key : $best_key")
println("\nDecrypted text:\n${decrypt(enc, best_key)}")
}</syntaxhighlight>
 
{{out}}
Note: carriage returns inserted into decrypted text after every 80 characters to make it more readable.
<pre>
Fit Length Key
2.984348 1 E <--- best so far
2.483684 2 EC <--- best so far
2.642487 3 TEE
1.976651 4 THEC <--- best so far
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW
 
Best key : THECHESHIRECAT
 
Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMB
LEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYS
ONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNA
TCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMT
REEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAM
ECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHR
OUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACK
ANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHE
CHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWER
ETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDIT
BUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-math}}
{{libheader|Wren-iterate}}
{{libheader|Wren-str}}
{{libheader|Wren-fmt}}
<syntaxhighlight lang="wren">import "./math" for Nums
import "./iterate" for Stepped
import "./str" for Char, Str
import "./fmt" for Fmt
 
var encoded =
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH" +
"VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD" +
"ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS" +
"FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG" +
"ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ" +
"ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS" +
"JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT" +
"LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST" +
"MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH" +
"QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV" +
"RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW" +
"TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO" +
"SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR" +
"ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX" +
"BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB" +
"BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA" +
"FWAML ZZRXJ EKAHV FASMU LVVUT TGK"
 
var freq = [
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074
]
 
var bestMatch = Fn.new { |a|
var sum = Nums.sum(a)
var bestFit = 1e100
var bestRotate = 0
for (rotate in 0..25) {
var fit = 0
for (i in 0..25) {
var d = a[(i + rotate) % 26] / sum - freq[i]
fit = fit + d * d / freq[i]
}
if (fit < bestFit) {
bestFit = fit
bestRotate = rotate
}
}
return bestRotate
}
 
var freqEveryNth = Fn.new { |msg, key|
var len = msg.count
var interval = key.count
var out = List.filled(26, 0)
var accu = List.filled(26, 0)
for (j in 0...interval) {
for (i in 0..25) out[i] = 0
for (i in Stepped.new(j...len, interval)) out[msg[i]] = out[msg[i]] + 1
var rot = bestMatch.call(out)
key[j] = Char.fromCode(rot + 65)
for (i in 0..25) accu[i] = accu[i] + out[(i + rot) % 26]
}
var sum = Nums.sum(accu)
var ret = 0
for (i in 0..25) {
var d = accu[i] / sum - freq[i]
ret = ret + d * d / freq[i]
}
return ret
}
 
var decrypt = Fn.new { |text, key|
var sb = ""
var ki = 0
for (c in text) {
if (Char.isAsciiUpper(c)) {
var ci = (c.bytes[0] - key[ki].bytes[0] + 26) % 26
sb = sb + Char.fromCode(ci + 65)
ki = (ki + 1) % key.count
}
}
return sb
}
 
var enc = encoded.replace(" ", "")
var txt = List.filled(enc.count, 0)
for (i in 0...txt.count) txt[i] = Char.code(enc[i]) - 65
var bestFit = 1e100
var bestKey = ""
var f = "$f $2d $s"
System.print(" Fit Length Key")
for (j in 1..26) {
var key = List.filled(j, "")
var fit = freqEveryNth.call(txt, key)
var sKey = key.join("")
Fmt.write(f, fit, j, sKey)
if (fit < bestFit) {
bestFit = fit
bestKey = sKey
System.write(" <--- best so far")
}
System.print()
}
System.print()
System.print("Best key : %(bestKey)")
System.print("\nDecrypted text:\n%(decrypt.call(enc, bestKey))")</syntaxhighlight>
 
{{out}}
<pre>
Fit Length Key
2.984348 1 E <--- best so far
2.483684 2 EC <--- best so far
2.642487 3 TEE
1.976651 4 THEC <--- best so far
2.356881 5 EEEPU
2.203129 6 TCECEC
1.051163 7 THECSAS <--- best so far
1.645763 8 TJQGAHET
2.001380 9 VEIZSEGNT
1.824476 10 ECEGAWQTDS
1.623083 11 TNLUSRXPTAJ
1.253527 12 XLECTHQGTHEC
1.399037 13 LJJTDGFNOTENR
0.152370 14 THECHESHIRECAT <--- best so far
1.533951 15 JNTOOEEXFTGQTNH
1.068182 16 TJTSAEETEXHPXHNE
1.034093 17 AZRAXUHEJLREEXIEE
1.443345 18 VNIZQPALEPTSXSEXUC
1.090977 19 FUCAITCSLVTEZDUDEHS
0.979868 20 EQXGAHWTTQECEWUGXHPI
0.789410 21 HVRCSAFTHEBDLSTAERSES
0.881380 22 TVIJTCIGKAQPELECRXPTNC
0.952456 23 KKEQXGPWTCQEELIEHXUWASV
0.715968 24 ELAIXHQTTIEDXJETTNTGAEPC
0.891258 25 OTJUUEGERDNQTUQEAGWUTIEOA
0.852784 26 IGITEGECAGAVUNLJAHASAVTETW
 
Best key : THECHESHIRECAT
 
Decrypted text:
THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
</pre>
 
=={{header|zkl}}==
{{trans|Python}}
<syntaxhighlight lang="zkl">var[const] uppercase=["A".."Z"].pump(String),
english_frequences=T( // A..Z
0.08167, 0.01492, 0.02782, 0.04253, 0.12702, 0.02228, 0.02015,
0.06094, 0.06966, 0.00153, 0.00772, 0.04025, 0.02406, 0.06749,
0.07507, 0.01929, 0.00095, 0.05987, 0.06327, 0.09056, 0.02758,
0.00978, 0.02360, 0.00150, 0.01974, 0.00074);
fcn vigenere_decrypt(target_freqs, input){ // ( (float,...), string)
nchars,ordA :=uppercase.len(),"A".toAsc();
sorted_targets:=target_freqs.sort();
frequency:='wrap(input){ // (n,n,n,n,...), n is ASCII index ("A"==65)
result:=uppercase.pump(List(),List.fp1(0)); // ( ("A",0),("B",0) ...)
foreach c in (input){ result[c - ordA][1] += 1 }
result // --> mutable list of mutable lists ( ("A",Int)...("Z",Int) )
};
correlation:='wrap(input){ // (n,n,n,n,...), n is ASCII index ("A"==65)
result,freq:=0.0, frequency(input);
freq.sort(fcn([(_,a)],[(_,b)]){ a<b }); // sort letters by frequency
foreach i,f in (freq.enumerate()){ result+=sorted_targets[i]*f[1] }
result // -->Float
};
cleaned:=input.toUpper().pump(List,uppercase.holds,Void.Filter,"toAsc");
best_len,best_corr := 0,-100.0;
# Assume that if there are less than 20 characters
# per column, the key's too long to guess
foreach i in ([2..cleaned.len()/20]){
pieces:=(i).pump(List,List.copy); // ( (),() ... )
foreach c in (cleaned){ pieces[__cWalker.idx%i].append(c) }
# The correlation seems to increase for smaller
# pieces/longer keys, so weigh against them a little
corr:=-0.5*i + pieces.apply(correlation).sum(0.0);
if(corr>best_corr) best_len,best_corr=i,corr;
}
if(best_len==0) return("Text is too short to analyze", "");
pieces:=best_len.pump(List,List.copy);
foreach c in (cleaned){ pieces[__cWalker.idx%best_len].append(c) }
key,freqs := "",pieces.apply(frequency);
foreach fr in (freqs){
fr.sort(fcn([(_,a)],[(_,b)]){ a>b }); // reverse sort by freq
m,max_corr := 0,0.0;
foreach j in (nchars){
corr,c := 0.0,ordA + j;
foreach frc in (fr){
d:=(frc[0].toAsc() - c + nchars) % nchars;
corr+=target_freqs[d]*frc[1];
if(corr>max_corr) m,max_corr=j,corr;
}
}
key+=(m + ordA).toChar();
}
cleaned.enumerate().apply('wrap([(i,c])){
( (c - (key[i%best_len]).toAsc() + nchars)%nchars + ordA ).toChar()
}).concat() :
T(key,_);
}</syntaxhighlight>
<syntaxhighlight lang="zkl">encryptedText:=
#<<<
"MOMUD EKAPV TQEFM OEVHP AJMII CDCTI FGYAG JSPXY ALUYM NSMYH
VUXJE LEPXJ FXGCM JHKDZ RYICU HYPUS PGIGM OIYHF WHTCQ KMLRD
ITLXZ LJFVQ GHOLW CUHLO MDSOE KTALU VYLNZ RFGBX PHVGA LWQIS
FGRPH JOOFW GUBYI LAPLA LCAFA AMKLG CETDW VOELJ IKGJB XPHVG
ALWQC SNWBU BYHCU HKOCE XJEYK BQKVY KIIEH GRLGH XEOLW AWFOJ
ILOVV RHPKD WIHKN ATUHN VRYAQ DIVHX FHRZV QWMWV LGSHN NLVZS
JLAKI FHXUF XJLXM TBLQV RXXHR FZXGV LRAJI EXPRV OSMNP KEPDT
LPRWM JAZPK LQUZA ALGZX GVLKL GJTUI ITDSU REZXJ ERXZS HMPST
MTEOE PAPJH SMFNB YVQUZ AALGA YDNMP AQOWT UHDBV TSMUE UIMVH
QGVRW AEFSP EMPVE PKXZY WLKJA GWALT VYYOB YIXOK IHPDS EVLEV
RVSGB JOGYW FHKBL GLXYA MVKIS KIEHY IMAPX UOISK PVAGN MZHPW
TTZPV XFCCD TUHJH WLAPF YULTB UXJLN SIJVV YOVDJ SOLXG TGRVO
SFRII CTMKO JFCQF KTINQ BWVHG TENLH HOGCS PSFPV GJOKM SIFPR
ZPAAS ATPTZ FTPPD PORRF TAXZP KALQA WMIUD BWNCT LEFKO ZQDLX
BUXJL ASIMR PNMBF ZCYLV WAPVF QRHZV ZGZEF KBYIO OFXYE VOWGB
BXVCB XBAWG LQKCM ICRRX MACUO IKHQU AJEGL OIJHH XPVZW JEWBA
FWAML ZZRXJ EKAHV FASMU LVVUT TGK";
#<<<
key,decoded:=vigenere_decrypt(english_frequences,encryptedText);
println("Key:", key);
println("Decoded text:", decoded);</syntaxhighlight>
{{out}}
<pre>
Key:THECHESHIRECAT
Decoded text:THISWASTHEPOEMTHATALICEREADJABBERWOCKYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEBEWARETHEJABBERWOCKMYSONTHEJAWSTHATBITETHECLAWSTHATCATCHBEWARETHEJUBJUBBIRDANDSHUNTHEFRUMIOUSBANDERSNATCHHETOOKHISVORPALSWORDINHANDLONGTIMETHEMANXOMEFOEHESOUGHTSORESTEDHEBYTHETUMTUMTREEANDSTOODAWHILEINTHOUGHTANDASINUFFISHTHOUGHTHESTOODTHEJABBERWOCKWITHEYESOFFLAMECAMEWHIFFLINGTHROUGHTHETULGEYWOODANDBURBLEDASITCAMEONETWOONETWOANDTHROUGHANDTHROUGHTHEVORPALBLADEWENTSNICKERSNACKHELEFTITDEADANDWITHITSHEADHEWENTGALUMPHINGBACKANDHASTTHOUSLAINTHEJABBERWOCKCOMETOMYARMSMYBEAMISHBOYOFRABJOUSDAYCALLOOHCALLAYHECHORTLEDINHISJOYTWASBRILLIGANDTHESLITHYTOVESDIDGYREANDGIMBLEINTHEWABEALLMIMSYWERETHEBOROGOVESANDTHEMOMERATHSOUTGRABEITSEEMSVERYPRETTYSHESAIDWHENSHEHADFINISHEDITBUTITSRATHERHARDTOUNDERSTAND
</pre>
9,476

edits