208 lines
4.9 KiB
Text
208 lines
4.9 KiB
Text
--
|
|
-- 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})
|