September 2017 Update
This commit is contained in:
parent
bba7bfd280
commit
ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions
|
|
@ -0,0 +1,93 @@
|
|||
import Data.List(transpose, nub, sort, maximumBy)
|
||||
import Data.Ord (comparing)
|
||||
import Data.Char (ord)
|
||||
|
||||
average :: Fractional a => [a] -> a
|
||||
average as = sum as / fromIntegral (length as)
|
||||
|
||||
-- Count the occurrence of a char in a string.
|
||||
countChar :: Eq a => [a] -> a -> Int
|
||||
countChar s c = length $ filter (==c) s
|
||||
|
||||
-- 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 = fmap (countChar str) (nub $ sort 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 actual = fmap (fromIntegral . countChar sample) ['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\
|
||||
\"
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
import Data.Map (fromListWith, toList)
|
||||
|
||||
main =
|
||||
mapM_ print (toList (fromListWith (+) (flip (,) 1 <$> filter (' ' /=) crypt)))
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
// 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)}")
|
||||
}
|
||||
|
|
@ -0,0 +1,208 @@
|
|||
--
|
||||
-- demo\rosetta\Cryptanalysis.exw
|
||||
--
|
||||
atom t0 = time()
|
||||
constant ciphertext = substitute_all("""
|
||||
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""",{" ","\n"},{"",""})
|
||||
|
||||
constant letters = new_dict(
|
||||
{{'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}})
|
||||
constant digraphs = new_dict(
|
||||
{{"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}})
|
||||
constant trigraphs = new_dict(
|
||||
{{"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}})
|
||||
|
||||
function decrypt(string enc, string key)
|
||||
integer keylen = length(key), k = 1
|
||||
string msg = repeat(' ', length(enc))
|
||||
for i=1 to length(enc) do
|
||||
msg[i] = mod(enc[i]-key[k]+26,26)+'A'
|
||||
k = mod(k,keylen)+1
|
||||
end for
|
||||
return msg
|
||||
end function
|
||||
|
||||
function cryptanalyze(string enc, integer maxkeylen=20)
|
||||
integer enclen = length(enc)
|
||||
string maxkey = "",
|
||||
maxdec = "",
|
||||
k1 = " "
|
||||
atom maxscore = 0.0
|
||||
|
||||
for keylen=1 to maxkeylen do
|
||||
string key = repeat(' ',keylen)
|
||||
sequence idx = {}
|
||||
for i=1 to enclen do
|
||||
if mod(i,keylen)=0 then
|
||||
idx &= i-keylen+1
|
||||
end if
|
||||
end for
|
||||
|
||||
for i=1 to keylen do
|
||||
atom maxsubscore = 0.0
|
||||
|
||||
for j='A' to 'Z' do
|
||||
atom subscore = 0.0
|
||||
|
||||
k1[1] = j
|
||||
string encidx = ""
|
||||
for ii=1 to length(idx) do
|
||||
encidx &= enc[idx[ii]]
|
||||
end for
|
||||
string dec = decrypt(encidx,k1)
|
||||
for di=1 to length(dec) do
|
||||
subscore += getd(dec[di],letters)
|
||||
end for
|
||||
|
||||
if subscore > maxsubscore then
|
||||
maxsubscore = subscore
|
||||
key[i] = j
|
||||
end if
|
||||
end for
|
||||
|
||||
idx = sq_add(idx,1)
|
||||
end for
|
||||
|
||||
string dec = decrypt(enc, key)
|
||||
atom score = 0.0
|
||||
|
||||
for i=1 to length(dec) do
|
||||
score += getd(dec[i],letters)
|
||||
end for
|
||||
|
||||
for i=1 to enclen - 2 do
|
||||
string digraph = dec[i..i+1]
|
||||
string trigraph = dec[i..i + 2]
|
||||
score += 2 * getd(digraph,digraphs)
|
||||
score += 3 * getd(trigraph,trigraphs)
|
||||
end for
|
||||
|
||||
if score > maxscore then
|
||||
maxscore = score
|
||||
maxkey = key
|
||||
maxdec = dec
|
||||
end if
|
||||
end for
|
||||
|
||||
return {maxkey,maxdec}
|
||||
end function
|
||||
|
||||
function fold(string s, integer w)
|
||||
for i=w to length(s) by w do
|
||||
s[i..i-1] = "\n"
|
||||
end for
|
||||
return s
|
||||
end function
|
||||
|
||||
string {key, dec} = cryptanalyze(ciphertext)
|
||||
printf(1,"key: %s\n\n%s\n\n", {key, fold(dec,80)})
|
||||
|
||||
printf(1,"elapsed time: %3.2f seconds",{time()-t0})
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
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,_);
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
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);
|
||||
Loading…
Add table
Add a link
Reference in a new issue