In this file, I decrypt some messages sent to me by students. > Example_sub:= "RWLFWARATEJLTJBNJLMYJLWJBKCLWBDLWDDTGJBMOTDJLTWFFKWACTJLWJLWDVMKATDJLTFWADGMYJLTHKDFWADGYMBJLMNGWADGMYOTWBGWGHMJLTBCMAYTGGMBRWLFWASBTGKDTDMXTBJLTCMNACKFWADJLNGJLTHKDFWADGNADTBLTBEWJCLWGHMJLTBCMAYTGGMBJLTHKDFWADGLWDYWFFTAJMBKCLWBDWGFMBDBWLFMYDLWBWWJFTWGJJLTFWADGELKCLLWDGMYWBGNBBTADTBTDJMLKHGLTRATEJLTQTATXMFTACTMYLKGWCJKMAGWADJLTATTDYMBJLTHQNJKJCTBJWKAFOLWDQTTAWSWKAYNFSWJLJMYMFFME"; > Example_sub := "RWLFWARATEJLTJBNJLMYJLWJBKCLWBDLWDDTGJBMOTDJLTWF\ FKWACTJLWJLWDVMKATDJLTFWADGMYJLTHKDFWADGYMBJLMNGWADGMYOTWB\ GWGHMJLTBCMAYTGGMBRWLFWASBTGKDTDMXTBJLTCMNACKFWADJLNGJLTHK\ DFWADGNADTBLTBEWJCLWGHMJLTBCMAYTGGMBJLTHKDFWADGLWDYWFFTAJM\ BKCLWBDWGFMBDBWLFMYDLWBWWJFTWGJJLTFWADGELKCLLWDGMYWBGNBBTA\ DTBTDJMLKHGLTRATEJLTQTATXMFTACTMYLKGWCJKMAGWADJLTATTDYMBJL\ THQNJKJCTBJWKAFOLWDQTTAWSWKAYNFSWJLJMYMFFME" > Example_Vigenere:="ZOJYOAHJKZBGXLSVZOJQTSDQTLXYNVXJUDJFAWYJKMNTYASQTVZVRHBXUSZPZLJTYOTYKKZRUBWUKJTPJTTTTPSIGSQJKJFTXPJFCHXCLSFKRHSFGWFEQVKLUBWPKFWCZPTPYIZVNLQQURJFMYNOGUIVUSIWYOJJGKHQSLYQLPLJZAMGWBJGTAZTTLIQAAYJKSTEGSBCXSTEQOFFXBNPKKMKYMFOOSDYOAMVGEJUJLGCAJMGJONUYPXVKYXCTKMCJKWKBLSJOTXGRMFPJONUVHWGTAXKTATNOCNPMPSCYOJNZLWVNHYYGZGCYPHCRSDCRHWIKIFUQLYYUYPKTNKTUTXWTBUVUZZPJVBPZVUCEAMGZHCGYOJERHNOKKYJKFXVOSQQCLICTKYJKFIKJUYFGYJHONMVHHHMCPYJEVZJUDJXKYNFGYJJKATNJTJKSHDFOLGWZPBKRSFVRLFUZIWKTNIQCUFUUSIKKYTHKCNNHLKQXLNFU"; Example_Vigenere := "ZOJYOAHJKZBGXLSVZOJQTSDQTLXYNVXJUDJFAWYJKMN\ TYASQTVZVRHBXUSZPZLJTYOTYKKZRUBWUKJTPJTTTTPSIGSQJKJFTXPJFC\ HXCLSFKRHSFGWFEQVKLUBWPKFWCZPTPYIZVNLQQURJFMYNOGUIVUSIWYOJ\ JGKHQSLYQLPLJZAMGWBJGTAZTTLIQAAYJKSTEGSBCXSTEQOFFXBNPKKMKY\ MFOOSDYOAMVGEJUJLGCAJMGJONUYPXVKYXCTKMCJKWKBLSJOTXGRMFPJON\ UVHWGTAXKTATNOCNPMPSCYOJNZLWVNHYYGZGCYPHCRSDCRHWIKIFUQLYYU\ YPKTNKTUTXWTBUVUZZPJVBPZVUCEAMGZHCGYOJERHNOKKYJKFXVOSQQCLI\ CTKYJKFIKJUYFGYJHONMVHHHMCPYJEVZJUDJXKYNFGYJJKATNJTJKSHDFO\ LGWZPBKRSFVRLFUZIWKTNIQCUFUUSIKKYTHKCNNHLKQXLNFU" > second_part:=(item,list) -> list; second_part := (item, list) -> list The frequency function tells how many times an item appears in a list > frequency:=(item,list)->if nops(list) = 0 then (item,0) else if list[1] = item then (item,1+second_part(frequency(item,list[2..nops(list)]))) else frequency(item,list[2..nops(list)]) end if end if; frequency := proc(item, list) option operator, arrow; if nops(list) = 0 then item, 0 else if list[1] = item then item, 1 + second_part( frequency(item, list[2 .. nops(list)])) else frequency(item, list[2 .. nops(list)]) end if end if end proc > with(StringTools); [AndMap, Capitalize, Char, CharacterMap, Chomp, CommonPrefix, CommonSuffix, Compare, CompareCI, Drop, Explode, FirstFromLeft, FirstFromRight, FormatMessage, Group, Implode, IsASCII, IsAlpha, IsAlphaNumeric, IsBinaryDigit, IsControlCharacter, IsDigit, IsGraphic, IsHexDigit, IsIdentifier, IsIdentifier1, IsLower, IsOctalDigit, IsPrefix, IsPrintable, IsPunctuation, IsSpace, IsSuffix, IsUpper, Join, LeftFold, Levenshtein, LongestCommonSubSequence, LongestCommonSubString, LowerCase, Map, OrMap, Ord, Random, RegMatch, RegSub, Remove, Reverse, RightFold, Search, SearchAll, Select, SelectRemove, Soundex, Split, Squeeze, SubString, Substitute, SubstituteAll, Take, Trim, TrimLeft, TrimRight, UpperCase] > frequency("A",Explode(Example_Vigenere)); "A", 13 The frequency_table function generates a frequency table telling how many times each item in the first list appears in the second. > frequency_table := (S,T) -> map((subs(s=(S),(x->frequency(x,s))),(T))); frequency_table := (S, T) -> map(subs(s = S, x -> frequency(x, s)), T) > Alphabet:="ABCDEFGHIJKLMNOPQRSTUVWXYZ"; Alphabet := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" > M:=frequency_table(Explode(Example_sub),Explode(Alphabet)); M := ["A", 27, "B", 25, "C", 12, "D", 29, "E", 5, "F", 20, "G", 24, "H", 7, "I", 0, "J", 33, "K", 16, "L", 37, "M", 27, "N", 8, "O", 3, "P", 0, "Q", 3, "R", 4, "S", 3, "T", 42, "U", 0, "V", 1, "W", 40, "X", 2, "Y", 13, "Z", 0] I develop the "bubble sort algorithm. > bubble_insert := (a,b,L) -> if nops(L) < 2 then [a,b] else if b sort_frequency_table:= L -> if nops(L) < 2 then L else bubble_insert(L[1],L[2],sort_frequency_table(L[3..nops(L)])) end if; sort_frequency_table := proc(L) option operator, arrow; if nops(L) < 2 then L else bubble_insert(L[1], L[2], sort_frequency_table(L[3 .. nops(L)])) end if end proc > sort_frequency_table(M); ["T", 42, "W", 40, "L", 37, "J", 33, "D", 29, "A", 27, "M", 27, "B", 25, "G", 24, "F", 20, "K", 16, "Y", 13, "C", 12, "N", 8, "H", 7, "E", 5, "R", 4, "O", 3, "Q", 3, "S", 3, "X", 2, "V", 1, "I", 0, "P", 0, "U", 0, "Z", 0] This is a better function for enciphering and deciphering with the Substitution Cipher. > partial_sub_cipher:=(list1,list2)->if nops(list1) < 2 or nops(list2) = 0 then list2 > else if list1[1] = list2[1] then [list1[2],op(partial_sub_cipher(list1,list2[2..nops(list2)]))] > else [op(partial_sub_cipher(list1[3..nops(list1)],[list2[1]])),op(partial_sub_cipher(list1,list2[2..nops(list2)]))]end if end if; partial_sub_cipher := proc(list1, list2) option operator, arrow; if nops(list1) < 2 or nops(list2) = 0 then list2 else if list1[1] = list2[1] then [list1[2], op( partial_sub_cipher(list1, list2[2 .. nops(list2)])) ] else [op(partial_sub_cipher(list1[3 .. nops(list1)], [list2[1]])), op(partial_sub_cipher(list1, list2[2 .. nops(list2)]))] end if end if end proc Here are some examples of trial attempts to work on > Implode(partial_sub_cipher(["T", "e", "W","t","A","h","X","z"],Explode(Example_sub))); "RtLFthRheEJLeJBNJLMYJLtJBKCLtBDLtDDeGJBMOeDJLetFFKthCeJLtJLtDVM\ KheDJLeFthDGMYJLeHKDFthDGYMBJLMNGthDGMYOetBGtGHMJLeBCMhYeG\ GMBRtLFthSBeGKDeDMzeBJLeCMNhCKFthDJLNGJLeHKDFthDGNhDeBLeBE\ tJCLtGHMJLeBCMhYeGGMBJLeHKDFthDGLtDYtFFehJMBKCLtBDtGFMBDBt\ LFMYDLtBttJFetGJJLeFthDGELKCLLtDGMYtBGNBBehDeBeDJMLKHGLeRh\ eEJLeQehezMFehCeMYLKGtCJKMhGthDJLeheeDYMBJLeHQNJKJCeBJtKhF\ OLtDQeehtStKhYNFStJLJMYMFFME" > > Implode(partial_sub_cipher(["T","t","W","e","L","a"],Explode(Example_sub))); "ReaFeARAtEJatJBNJaMYJaeJBKCaeBDaeDDtGJBMOtDJateFFKeACtJaeJaeDVM\ KAtDJatFeADGMYJatHKDFeADGYMBJaMNGeADGMYOteBGeGHMJatBCMAYtG\ GMBReaFeASBtGKDtDMXtBJatCMNACKFeADJaNGJatHKDFeADGNADtBatBE\ eJCaeGHMJatBCMAYtGGMBJatHKDFeADGaeDYeFFtAJMBKCaeBDeGFMBDBe\ aFMYDaeBeeJFteGJJatFeADGEaKCaaeDGMYeBGNBBtADtBtDJMaKHGatRA\ tEJatQtAtXMFtACtMYaKGeCJKMAGeADJatAttDYMBJatHQNJKJCtBJeKAF\ OaeDQttAeSeKAYNFSeJaJMYMFFME" > dropL := (item,list) -> if nops(list) = 0 then list else if list[1] = item then dropL(item,list[2..nops(list)]) else [list[1],op(dropL(item,list[2..nops(list)]))]end if end if; > > dropL := proc(item, list) option operator, arrow; if nops(list) = 0 then list else if list[1] = item then dropL(item, list[2 .. nops(list)]) else [list[1], op(dropL(item, list[2 .. nops(list)]))] end if end if end proc This function generates a frequency table of the items in the list L. It doesn't need an "alphabet" argument. > self_count := L -> if nops(L) = 0 then L else [op(frequency_table(L,[L[1]])),op(self_count(dropL(L[1],L[2..nops(L)])))] end if; self_count := proc(L) option operator, arrow; if nops(L) = 0 then L else [op(frequency_table(L, [L[1]])), op(self_count(dropL(L[1], L[2 .. nops(L)])))] end if end proc > self_count(Explode(Example_sub)); ["R", 4, "W", 40, "L", 37, "F", 20, "A", 27, "T", 42, "E", 5, "J", 33, "B", 25, "N", 8, "M", 27, "Y", 13, "K", 16, "C", 12, "D", 29, "G", 24, "O", 3, "V", 1, "H", 7, "S", 3, "X", 2, "Q", 3] > self_count(["a","a","b","a"]); ["a", 3, "b", 1] > This function generates a list of "digrams" (two letter sequences) from the text list L. > digrams := L -> if nops(L) < 2 then [] else [[L[1],L[2]],op(digrams(L[2..nops(L)]))] end if; digrams := proc(L) option operator, arrow; if nops(L) < 2 then [] else [[L[1], L[2]], op(digrams(L[2 .. nops(L)]))] end if end proc > digrams (Explode(Alphabet)); [["A", "B"], ["B", "C"], ["C", "D"], ["D", "E"], ["E", "F"], ["F", "G"], ["G", "H"], ["H", "I"], ["I", "J"], ["J", "K"], ["K", "L"], ["L", "M"], ["M", "N"], ["N", "O"], ["O", "P"], ["P", "Q"], ["Q", "R"], ["R", "S"], ["S", "T"], ["T", "U"], ["U", "V"], ["V", "W"], ["W", "X"], ["X", "Y"], ["Y", "Z"]] > self_count(digrams(Explode(Example_sub))); [["R", "W"], 2, ["W", "L"], 3, ["L", "F"], 3, ["F", "W"], 8, ["W", "A"], 11, ["A", "R"], 1, ["R", "A"], 2, ["A", "T"], 5, ["T", "E"], 2, ["E", "J"], 2, ["J", "L"], 20, ["L", "T"], 15, ["T", "J"], 2, ["J", "B"], 3, ["B", "N"], 1, ["N", "J"], 2, ["L", "M"], 2, ["M", "Y"], 7, ["Y", "J"], 2, ["L", "W"], 11, ["W", "J"], 5, ["B", "K"], 2, ["K", "C"], 3, ["C", "L"], 4, ["W", "B"], 5, ["B", "D"], 3, ["D", "L"], 2, ["W", "D"], 5, ["D", "D"], 1, ["D", "T"], 4, ["T", "G"], 4, ["G", "J"], 3, ["B", "M"], 1, ["M", "O"], 1, ["O", "T"], 2, ["T", "D"], 5, ["D", "J"], 5, ["T", "W"], 3, ["W", "F"], 2, ["F", "F"], 3, ["F", "K"], 1, ["K", "W"], 1, ["A", "C"], 3, ["C", "T"], 3, ["D", "V"], 1, ["V", "M"], 1, ["M", "K"], 1, ["K", "A"], 3, ["T", "F"], 2, ["A", "D"], 10, ["D", "G"], 7, ["G", "M"], 5, ["T", "H"], 4, ["H", "K"], 3, ["K", "D"], 4, ["D", "F"], 3, ["G", "Y"], 1, ["Y", "M"], 3, ["M", "B"], 6, ["B", "J"], 5, ["M", "N"], 2, ["N", "G"], 2, ["G", "W"], 4, ["Y", "O"], 1, ["B", "G"], 2, ["W", "G"], 4, ["G", "H"], 2, ["H", "M"], 2, ["M", "J"], 2, ["T", "B"], 7, ["B", "C"], 2, ["C", "M"], 3, ["M", "A"], 3, ["A", "Y"], 3, ["Y", "T"], 2, ["G", "G"], 2, ["B", "R"], 1, ["A", "S"], 1, ["S", "B"], 1, ["B", "T"], 3, ["G", "K"], 1, ["D", "M"], 1, ["M", "X"], 1, ["X", "T"], 1, ["T", "C"], 1, ["N", "A"], 2, ["C", "K"], 1, ["K", "F"], 1, ["L", "N"], 1, ["G", "N"], 2, ["B", "L"], 1, ["B", "E"], 1, ["E", "W"], 1, ["J", "C"], 2, ["G", "L"], 2, ["D", "Y"], 2, ["Y", "W"], 2, ["F", "T"], 3, ["T", "A"], 6, ["A", "J"], 1, ["J", "M"], 3, ["D", "W"], 1, ["G", "F"], 1, ["F", "M"], 3, ["D", "B"], 1, ["B", "W"], 2, ["Y", "D"], 1, ["W", "W"], 1, ["J", "F"], 1, ["J", "J"], 1, ["G", "E"], 1, ["E", "L"], 1, ["L", "K"], 3, ["L", "L"], 1, ["N", "B"], 1, ["B", "B"], 1, ["M", "L"], 1, ["K", "H"], 1, ["H", "G"], 1, ["T", "R"], 1, ["T", "Q"], 1, ["Q", "T"], 2, ["T", "X"], 1, ["X", "M"], 1, ["M", "F"], 2, ["T", "M"], 1, ["Y", "L"], 1, ["K", "G"], 1, ["W", "C"], 1, ["C", "J"], 1, ["J", "K"], 2, ["K", "M"], 1, ["A", "G"], 1, ["T", "T"], 2, ["H", "Q"], 1, ["Q", "N"], 1, ["K", "J"], 1, ["J", "W"], 1, ["W", "K"], 2, ["A", "F"], 1, ["F", "O"], 1, ["O", "L"], 1, ["D", "Q"], 1, ["A", "W"], 1, ["W", "S"], 1, ["S", "W"], 2, ["Y", "N"], 1, ["N", "F"], 1, ["F", "S"], 1, ["L", "J"], 1, ["M", "E"], 1] > sort_frequency_table(%); [["J", "L"], 20, ["L", "T"], 15, ["W", "A"], 11, ["L", "W"], 11, ["A", "D"], 10, ["F", "W"], 8, ["M", "Y"], 7, ["D", "G"], 7, ["T", "B"], 7, ["M", "B"], 6, ["T", "A"], 6, ["A", "T"], 5, ["W", "J"], 5, ["W", "B"], 5, ["W", "D"], 5, ["T", "D"], 5, ["D", "J"], 5, ["G", "M"], 5, ["B", "J"], 5, ["C", "L"], 4, ["D", "T"], 4, ["T", "G"], 4, ["T", "H"], 4, ["K", "D"], 4, ["G", "W"], 4, ["W", "G"], 4, ["W", "L"], 3, ["L", "F"], 3, ["J", "B"], 3, ["K", "C"], 3, ["B", "D"], 3, ["G", "J"], 3, ["T", "W"], 3, ["F", "F"], 3, ["A", "C"], 3, ["C", "T"], 3, ["K", "A"], 3, ["H", "K"], 3, ["D", "F"], 3, ["Y", "M"], 3, ["C", "M"], 3, ["M", "A"], 3, ["A", "Y"], 3, ["B", "T"], 3, ["F", "T"], 3, ["J", "M"], 3, ["F", "M"], 3, ["L", "K"], 3, ["R", "W"], 2, ["R", "A"], 2, ["T", "E"], 2, ["E", "J"], 2, ["T", "J"], 2, ["N", "J"], 2, ["L", "M"], 2, ["Y", "J"], 2, ["B", "K"], 2, ["D", "L"], 2, ["O", "T"], 2, ["W", "F"], 2, ["T", "F"], 2, ["M", "N"], 2, ["N", "G"], 2, ["B", "G"], 2, ["G", "H"], 2, ["H", "M"], 2, ["M", "J"], 2, ["B", "C"], 2, ["Y", "T"], 2, ["G", "G"], 2, ["N", "A"], 2, ["G", "N"], 2, ["J", "C"], 2, ["G", "L"], 2, ["D", "Y"], 2, ["Y", "W"], 2, ["B", "W"], 2, ["Q", "T"], 2, ["M", "F"], 2, ["J", "K"], 2, ["T", "T"], 2, ["W", "K"], 2, ["S", "W"], 2, ["A", "R"], 1, ["B", "N"], 1, ["D", "D"], 1, ["B", "M"], 1, ["M", "O"], 1, ["F", "K"], 1, ["K", "W"], 1, ["D", "V"], 1, ["V", "M"], 1, ["M", "K"], 1, ["G", "Y"], 1, ["Y", "O"], 1, ["B", "R"], 1, ["A", "S"], 1, ["S", "B"], 1, ["G", "K"], 1, ["D", "M"], 1, ["M", "X"], 1, ["X", "T"], 1, ["T", "C"], 1, ["C", "K"], 1, ["K", "F"], 1, ["L", "N"], 1, ["B", "L"], 1, ["B", "E"], 1, ["E", "W"], 1, ["A", "J"], 1, ["D", "W"], 1, ["G", "F"], 1, ["D", "B"], 1, ["Y", "D"], 1, ["W", "W"], 1, ["J", "F"], 1, ["J", "J"], 1, ["G", "E"], 1, ["E", "L"], 1, ["L", "L"], 1, ["N", "B"], 1, ["B", "B"], 1, ["M", "L"], 1, ["K", "H"], 1, ["H", "G"], 1, ["T", "R"], 1, ["T", "Q"], 1, ["T", "X"], 1, ["X", "M"], 1, ["T", "M"], 1, ["Y", "L"], 1, ["K", "G"], 1, ["W", "C"], 1, ["C", "J"], 1, ["K", "M"], 1, ["A", "G"], 1, ["H", "Q"], 1, ["Q", "N"], 1, ["K", "J"], 1, ["J", "W"], 1, ["A", "F"], 1, ["F", "O"], 1, ["O", "L"], 1, ["D", "Q"], 1, ["A", "W"], 1, ["W", "S"], 1, ["Y", "N"], 1, ["N", "F"], 1, ["F", "S"], 1, ["L", "J"], 1, ["M", "E"], 1] > trigrams:= L->if nops(L) < 3 then [] else [[L[1],L[2],L[3]],op(trigrams(L[2..nops(L)]))] end if; trigrams := proc(L) option operator, arrow; if nops(L) < 3 then [] else [[L[1], L[2], L[3]], op(trigrams(L[2 .. nops(L)]))] end if end proc > self_count(trigrams(Explode(Example_sub))); [["R", "W", "L"], 2, ["W", "L", "F"], 3, ["L", "F", "W"], 2, ["F", "W", "A"], 8, ["W", "A", "R"], 1, ["A", "R", "A"], 1, ["R", "A", "T"], 2, ["A", "T", "E"], 2, ["T", "E", "J"], 2, ["E", "J", "L"], 2, ["J", "L", "T"], 13, ["L", "T", "J"], 1, ["T", "J", "B"], 1, ["J", "B", "N"], 1, ["B", "N", "J"], 1, ["N", "J", "L"], 1, ["J", "L", "M"], 2, ["L", "M", "Y"], 1, ["M", "Y", "J"], 2, ["Y", "J", "L"], 2, ["J", "L", "W"], 3, ["L", "W", "J"], 2, ["W", "J", "B"], 1, ["J", "B", "K"], 1, ["B", "K", "C"], 2, ["K", "C", "L"], 3, ["C", "L", "W"], 3, ["L", "W", "B"], 3, ["W", "B", "D"], 2, ["B", "D", "L"], 1, ["D", "L", "W"], 2, ["L", "W", "D"], 5, ["W", "D", "D"], 1, ["D", "D", "T"], 1, ["D", "T", "G"], 1, ["T", "G", "J"], 1, ["G", "J", "B"], 1, ["J", "B", "M"], 1, ["B", "M", "O"], 1, ["M", "O", "T"], 1, ["O", "T", "D"], 1, ["T", "D", "J"], 3, ["D", "J", "L"], 4, ["L", "T", "W"], 1, ["T", "W", "F"], 1, ["W", "F", "F"], 2, ["F", "F", "K"], 1, ["F", "K", "W"], 1, ["K", "W", "A"], 1, ["W", "A", "C"], 1, ["A", "C", "T"], 2, ["C", "T", "J"], 1, ["T", "J", "L"], 1, ["W", "J", "L"], 2, ["W", "D", "V"], 1, ["D", "V", "M"], 1, ["V", "M", "K"], 1, ["M", "K", "A"], 1, ["K", "A", "T"], 1, ["A", "T", "D"], 1, ["L", "T", "F"], 2, ["T", "F", "W"], 2, ["W", "A", "D"], 8, ["A", "D", "G"], 6, ["D", "G", "M"], 3, ["G", "M", "Y"], 3, ["L", "T", "H"], 4, ["T", "H", "K"], 3, ["H", "K", "D"], 3, ["K", "D", "F"], 3, ["D", "F", "W"], 3, ["D", "G", "Y"], 1, ["G", "Y", "M"], 1, ["Y", "M", "B"], 2, ["M", "B", "J"], 3, ["B", "J", "L"], 4, ["L", "M", "N"], 1, ["M", "N", "G"], 1, ["N", "G", "W"], 1, ["G", "W", "A"], 2, ["M", "Y", "O"], 1, ["Y", "O", "T"], 1, ["O", "T", "W"], 1, ["T", "W", "B"], 1, ["W", "B", "G"], 2, ["B", "G", "W"], 1, ["G", "W", "G"], 1, ["W", "G", "H"], 2, ["G", "H", "M"], 2, ["H", "M", "J"], 2, ["M", "J", "L"], 2, ["L", "T", "B"], 3, ["T", "B", "C"], 2, ["B", "C", "M"], 2, ["C", "M", "A"], 2, ["M", "A", "Y"], 2, ["A", "Y", "T"], 2, ["Y", "T", "G"], 2, ["T", "G", "G"], 2, ["G", "G", "M"], 2, ["G", "M", "B"], 2, ["M", "B", "R"], 1, ["B", "R", "W"], 1, ["W", "A", "S"], 1, ["A", "S", "B"], 1, ["S", "B", "T"], 1, ["B", "T", "G"], 1, ["T", "G", "K"], 1, ["G", "K", "D"], 1, ["K", "D", "T"], 1, ["D", "T", "D"], 1, ["T", "D", "M"], 1, ["D", "M", "X"], 1, ["M", "X", "T"], 1, ["X", "T", "B"], 1, ["T", "B", "J"], 2, ["L", "T", "C"], 1, ["T", "C", "M"], 1, ["C", "M", "N"], 1, ["M", "N", "A"], 1, ["N", "A", "C"], 1, ["A", "C", "K"], 1, ["C", "K", "F"], 1, ["K", "F", "W"], 1, ["A", "D", "J"], 2, ["J", "L", "N"], 1, ["L", "N", "G"], 1, ["N", "G", "J"], 1, ["G", "J", "L"], 1, ["D", "G", "N"], 1, ["G", "N", "A"], 1, ["N", "A", "D"], 1, ["A", "D", "T"], 2, ["D", "T", "B"], 2, ["T", "B", "L"], 1, ["B", "L", "T"], 1, ["T", "B", "E"], 1, ["B", "E", "W"], 1, ["E", "W", "J"], 1, ["W", "J", "C"], 1, ["J", "C", "L"], 1, ["L", "W", "G"], 1, ["D", "G", "L"], 1, ["G", "L", "W"], 1, ["W", "D", "Y"], 1, ["D", "Y", "W"], 1, ["Y", "W", "F"], 1, ["F", "F", "T"], 1, ["F", "T", "A"], 2, ["T", "A", "J"], 1, ["A", "J", "M"], 1, ["J", "M", "B"], 1, ["M", "B", "K"], 1, ["B", "D", "W"], 1, ["D", "W", "G"], 1, ["W", "G", "F"], 1, ["G", "F", "M"], 1, ["F", "M", "B"], 1, ["M", "B", "D"], 1, ["B", "D", "B"], 1, ["D", "B", "W"], 1, ["B", "W", "L"], 1, ["L", "F", "M"], 1, ["F", "M", "Y"], 1, ["M", "Y", "D"], 1, ["Y", "D", "L"], 1, ["W", "B", "W"], 1, ["B", "W", "W"], 1, ["W", "W", "J"], 1, ["W", "J", "F"], 1, ["J", "F", "T"], 1, ["F", "T", "W"], 1, ["T", "W", "G"], 1, ["W", "G", "J"], 1, ["G", "J", "J"], 1, ["J", "J", "L"], 1, ["D", "G", "E"], 1, ["G", "E", "L"], 1, ["E", "L", "K"], 1, ["L", "K", "C"], 1, ["C", "L", "L"], 1, ["L", "L", "W"], 1, ["W", "D", "G"], 1, ["M", "Y", "W"], 1, ["Y", "W", "B"], 1, ["B", "G", "N"], 1, ["G", "N", "B"], 1, ["N", "B", "B"], 1, ["B", "B", "T"], 1, ["B", "T", "A"], 1, ["T", "A", "D"], 1, ["T", "B", "T"], 1, ["B", "T", "D"], 1, ["D", "J", "M"], 1, ["J", "M", "L"], 1, ["M", "L", "K"], 1, ["L", "K", "H"], 1, ["K", "H", "G"], 1, ["H", "G", "L"], 1, ["G", "L", "T"], 1, ["L", "T", "R"], 1, ["T", "R", "A"], 1, ["L", "T", "Q"], 1, ["T", "Q", "T"], 1, ["Q", "T", "A"], 1, ["T", "A", "T"], 2, ["A", "T", "X"], 1, ["T", "X", "M"], 1, ["X", "M", "F"], 1, ["M", "F", "T"], 1, ["T", "A", "C"], 1, ["C", "T", "M"], 1, ["T", "M", "Y"], 1, ["M", "Y", "L"], 1, ["Y", "L", "K"], 1, ["L", "K", "G"], 1, ["K", "G", "W"], 1, ["G", "W", "C"], 1, ["W", "C", "J"], 1, ["C", "J", "K"], 1, ["J", "K", "M"], 1, ["K", "M", "A"], 1, ["M", "A", "G"], 1, ["A", "G", "W"], 1, ["L", "T", "A"], 1, ["A", "T", "T"], 1, ["T", "T", "D"], 1, ["T", "D", "Y"], 1, ["D", "Y", "M"], 1, ["T", "H", "Q"], 1, ["H", "Q", "N"], 1, ["Q", "N", "J"], 1, ["N", "J", "K"], 1, ["J", "K", "J"], 1, ["K", "J", "C"], 1, ["J", "C", "T"], 1, ["C", "T", "B"], 1, ["B", "J", "W"], 1, ["J", "W", "K"], 1, ["W", "K", "A"], 2, ["K", "A", "F"], 1, ["A", "F", "O"], 1, ["F", "O", "L"], 1, ["O", "L", "W"], 1, ["W", "D", "Q"], 1, ["D", "Q", "T"], 1, ["Q", "T", "T"], 1, ["T", "T", "A"], 1, ["T", "A", "W"], 1, ["A", "W", "S"], 1, ["W", "S", "W"], 1, ["S", "W", "K"], 1, ["K", "A", "Y"], 1, ["A", "Y", "N"], 1, ["Y", "N", "F"], 1, ["N", "F", "S"], 1, ["F", "S", "W"], 1, ["S", "W", "J"], 1, ["J", "L", "J"], 1, ["L", "J", "M"], 1, ["J", "M", "Y"], 1, ["M", "Y", "M"], 1, ["Y", "M", "F"], 1, ["M", "F", "F"], 1, ["F", "F", "M"], 1, ["F", "M", "E"], 1] > sort_frequency_table(%); [["J", "L", "T"], 13, ["F", "W", "A"], 8, ["W", "A", "D"], 8, ["A", "D", "G"], 6, ["L", "W", "D"], 5, ["D", "J", "L"], 4, ["L", "T", "H"], 4, ["B", "J", "L"], 4, ["W", "L", "F"], 3, ["J", "L", "W"], 3, ["K", "C", "L"], 3, ["C", "L", "W"], 3, ["L", "W", "B"], 3, ["T", "D", "J"], 3, ["D", "G", "M"], 3, ["G", "M", "Y"], 3, ["T", "H", "K"], 3, ["H", "K", "D"], 3, ["K", "D", "F"], 3, ["D", "F", "W"], 3, ["M", "B", "J"], 3, ["L", "T", "B"], 3, ["R", "W", "L"], 2, ["L", "F", "W"], 2, ["R", "A", "T"], 2, ["A", "T", "E"], 2, ["T", "E", "J"], 2, ["E", "J", "L"], 2, ["J", "L", "M"], 2, ["M", "Y", "J"], 2, ["Y", "J", "L"], 2, ["L", "W", "J"], 2, ["B", "K", "C"], 2, ["W", "B", "D"], 2, ["D", "L", "W"], 2, ["W", "F", "F"], 2, ["A", "C", "T"], 2, ["W", "J", "L"], 2, ["L", "T", "F"], 2, ["T", "F", "W"], 2, ["Y", "M", "B"], 2, ["G", "W", "A"], 2, ["W", "B", "G"], 2, ["W", "G", "H"], 2, ["G", "H", "M"], 2, ["H", "M", "J"], 2, ["M", "J", "L"], 2, ["T", "B", "C"], 2, ["B", "C", "M"], 2, ["C", "M", "A"], 2, ["M", "A", "Y"], 2, ["A", "Y", "T"], 2, ["Y", "T", "G"], 2, ["T", "G", "G"], 2, ["G", "G", "M"], 2, ["G", "M", "B"], 2, ["T", "B", "J"], 2, ["A", "D", "J"], 2, ["A", "D", "T"], 2, ["D", "T", "B"], 2, ["F", "T", "A"], 2, ["T", "A", "T"], 2, ["W", "K", "A"], 2, ["W", "A", "R"], 1, ["A", "R", "A"], 1, ["L", "T", "J"], 1, ["T", "J", "B"], 1, ["J", "B", "N"], 1, ["B", "N", "J"], 1, ["N", "J", "L"], 1, ["L", "M", "Y"], 1, ["W", "J", "B"], 1, ["J", "B", "K"], 1, ["B", "D", "L"], 1, ["W", "D", "D"], 1, ["D", "D", "T"], 1, ["D", "T", "G"], 1, ["T", "G", "J"], 1, ["G", "J", "B"], 1, ["J", "B", "M"], 1, ["B", "M", "O"], 1, ["M", "O", "T"], 1, ["O", "T", "D"], 1, ["L", "T", "W"], 1, ["T", "W", "F"], 1, ["F", "F", "K"], 1, ["F", "K", "W"], 1, ["K", "W", "A"], 1, ["W", "A", "C"], 1, ["C", "T", "J"], 1, ["T", "J", "L"], 1, ["W", "D", "V"], 1, ["D", "V", "M"], 1, ["V", "M", "K"], 1, ["M", "K", "A"], 1, ["K", "A", "T"], 1, ["A", "T", "D"], 1, ["D", "G", "Y"], 1, ["G", "Y", "M"], 1, ["L", "M", "N"], 1, ["M", "N", "G"], 1, ["N", "G", "W"], 1, ["M", "Y", "O"], 1, ["Y", "O", "T"], 1, ["O", "T", "W"], 1, ["T", "W", "B"], 1, ["B", "G", "W"], 1, ["G", "W", "G"], 1, ["M", "B", "R"], 1, ["B", "R", "W"], 1, ["W", "A", "S"], 1, ["A", "S", "B"], 1, ["S", "B", "T"], 1, ["B", "T", "G"], 1, ["T", "G", "K"], 1, ["G", "K", "D"], 1, ["K", "D", "T"], 1, ["D", "T", "D"], 1, ["T", "D", "M"], 1, ["D", "M", "X"], 1, ["M", "X", "T"], 1, ["X", "T", "B"], 1, ["L", "T", "C"], 1, ["T", "C", "M"], 1, ["C", "M", "N"], 1, ["M", "N", "A"], 1, ["N", "A", "C"], 1, ["A", "C", "K"], 1, ["C", "K", "F"], 1, ["K", "F", "W"], 1, ["J", "L", "N"], 1, ["L", "N", "G"], 1, ["N", "G", "J"], 1, ["G", "J", "L"], 1, ["D", "G", "N"], 1, ["G", "N", "A"], 1, ["N", "A", "D"], 1, ["T", "B", "L"], 1, ["B", "L", "T"], 1, ["T", "B", "E"], 1, ["B", "E", "W"], 1, ["E", "W", "J"], 1, ["W", "J", "C"], 1, ["J", "C", "L"], 1, ["L", "W", "G"], 1, ["D", "G", "L"], 1, ["G", "L", "W"], 1, ["W", "D", "Y"], 1, ["D", "Y", "W"], 1, ["Y", "W", "F"], 1, ["F", "F", "T"], 1, ["T", "A", "J"], 1, ["A", "J", "M"], 1, ["J", "M", "B"], 1, ["M", "B", "K"], 1, ["B", "D", "W"], 1, ["D", "W", "G"], 1, ["W", "G", "F"], 1, ["G", "F", "M"], 1, ["F", "M", "B"], 1, ["M", "B", "D"], 1, ["B", "D", "B"], 1, ["D", "B", "W"], 1, ["B", "W", "L"], 1, ["L", "F", "M"], 1, ["F", "M", "Y"], 1, ["M", "Y", "D"], 1, ["Y", "D", "L"], 1, ["W", "B", "W"], 1, ["B", "W", "W"], 1, ["W", "W", "J"], 1, ["W", "J", "F"], 1, ["J", "F", "T"], 1, ["F", "T", "W"], 1, ["T", "W", "G"], 1, ["W", "G", "J"], 1, ["G", "J", "J"], 1, ["J", "J", "L"], 1, ["D", "G", "E"], 1, ["G", "E", "L"], 1, ["E", "L", "K"], 1, ["L", "K", "C"], 1, ["C", "L", "L"], 1, ["L", "L", "W"], 1, ["W", "D", "G"], 1, ["M", "Y", "W"], 1, ["Y", "W", "B"], 1, ["B", "G", "N"], 1, ["G", "N", "B"], 1, ["N", "B", "B"], 1, ["B", "B", "T"], 1, ["B", "T", "A"], 1, ["T", "A", "D"], 1, ["T", "B", "T"], 1, ["B", "T", "D"], 1, ["D", "J", "M"], 1, ["J", "M", "L"], 1, ["M", "L", "K"], 1, ["L", "K", "H"], 1, ["K", "H", "G"], 1, ["H", "G", "L"], 1, ["G", "L", "T"], 1, ["L", "T", "R"], 1, ["T", "R", "A"], 1, ["L", "T", "Q"], 1, ["T", "Q", "T"], 1, ["Q", "T", "A"], 1, ["A", "T", "X"], 1, ["T", "X", "M"], 1, ["X", "M", "F"], 1, ["M", "F", "T"], 1, ["T", "A", "C"], 1, ["C", "T", "M"], 1, ["T", "M", "Y"], 1, ["M", "Y", "L"], 1, ["Y", "L", "K"], 1, ["L", "K", "G"], 1, ["K", "G", "W"], 1, ["G", "W", "C"], 1, ["W", "C", "J"], 1, ["C", "J", "K"], 1, ["J", "K", "M"], 1, ["K", "M", "A"], 1, ["M", "A", "G"], 1, ["A", "G", "W"], 1, ["L", "T", "A"], 1, ["A", "T", "T"], 1, ["T", "T", "D"], 1, ["T", "D", "Y"], 1, ["D", "Y", "M"], 1, ["T", "H", "Q"], 1, ["H", "Q", "N"], 1, ["Q", "N", "J"], 1, ["N", "J", "K"], 1, ["J", "K", "J"], 1, ["K", "J", "C"], 1, ["J", "C", "T"], 1, ["C", "T", "B"], 1, ["B", "J", "W"], 1, ["J", "W", "K"], 1, ["K", "A", "F"], 1, ["A", "F", "O"], 1, ["F", "O", "L"], 1, ["O", "L", "W"], 1, ["W", "D", "Q"], 1, ["D", "Q", "T"], 1, ["Q", "T", "T"], 1, ["T", "T", "A"], 1, ["T", "A", "W"], 1, ["A", "W", "S"], 1, ["W", "S", "W"], 1, ["S", "W", "K"], 1, ["K", "A", "Y"], 1, ["A", "Y", "N"], 1, ["Y", "N", "F"], 1, ["N", "F", "S"], 1, ["F", "S", "W"], 1, ["S", "W", "J"], 1, ["J", "L", "J"], 1, ["L", "J", "M"], 1, ["J", "M", "Y"], 1, ["M", "Y", "M"], 1, ["Y", "M", "F"], 1, ["M", "F", "F"], 1, ["F", "F", "M"], 1, ["F", "M", "E"], 1] > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b","M","o","Y","f","B", "r","G","s","N","u","O","y","F","l","C","c","K","i","V","j","H","m","E","w","R","k","X","v","S","p"],Explode(Example_sub))); "kahlanknewthetruthofthatrichardhaddestroyedthealliancethathadjo\ inedthelandsofthemidlandsforthousandsofyearsasmotherconfes\ sorkahlanpresidedoverthecouncilandthusthemidlandsunderherw\ atchasmotherconfessorthemidlandshadfallentorichardaslordra\ hlofdharaatleastthelandswhichhadsofarsurrenderedtohimshekn\ ewthebenevolenceofhisactionsandtheneedforthembutitcertainl\ yhadbeenapainfulpathtofollow" > sort_frequency_table(M); # this is the frequency table from above -- I used it for reference. ["T", 42, "W", 40, "L", 37, "J", 33, "D", 29, "A", 27, "M", 27, "B", 25, "G", 24, "F", 20, "K", 16, "Y", 13, "C", 12, "N", 8, "H", 7, "E", 5, "R", 4, "O", 3, "Q", 3, "S", 3, "X", 2, "V", 1, "I", 0, "P", 0, "U", 0, "Z", 0] > # it was the trigram frequency table that gave me the right insight on this -- once I saw that > # JLT was "the" and WAD was "and" the rest was a matter of recognizing words. Not quite -- > # I spotted "b" because of the word "been", then I used frequency to guess "o" and guessed "f" > # because I thought I saw "of" -- then it reduced to deciphering words. A step by step deciphering follows: First, JLT is probably "the" > Implode(partial_sub_cipher(["J","t","L","h","T","e"],Explode(Example_sub))); "RWhFWARAeEthetBNthMYthWtBKChWBDhWDDeGtBMOeDtheWFFKWACethWthWDVM\ KAeDtheFWADGMYtheHKDFWADGYMBthMNGWADGMYOeWBGWGHMtheBCMAYeG\ GMBRWhFWASBeGKDeDMXeBtheCMNACKFWADthNGtheHKDFWADGNADeBheBE\ WtChWGHMtheBCMAYeGGMBtheHKDFWADGhWDYWFFeAtMBKChWBDWGFMBDBW\ hFMYDhWBWWtFeWGttheFWADGEhKChhWDGMYWBGNBBeADeBeDtMhKHGheRA\ eEtheQeAeXMFeACeMYhKGWCtKMAGWADtheAeeDYMBtheHQNtKtCeBtWKAF\ OhWDQeeAWSWKAYNFSWthtMYMFFME" I omit some false starts here. As soon as I tried WAD = "and", plaintext started popping out! > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d"],Explode(Example_sub))); "RahFanRneEthetBNthMYthatBKChaBdhaddeGtBMOedtheaFFKanCethathadVM\ KnedtheFandGMYtheHKdFandGYMBthMNGandGMYOeaBGaGHMtheBCMnYeG\ GMBRahFanSBeGKdedMXeBtheCMNnCKFandthNGtheHKdFandGNndeBheBE\ atChaGHMtheBCMnYeGGMBtheHKdFandGhadYaFFentMBKChaBdaGFMBdBa\ hFMYdhaBaatFeaGttheFandGEhKChhadGMYaBGNBBendeBedtMhKHGheRn\ eEtheQeneXMFenCeMYhKGaCtKMnGandtheneedYMBtheHQNtKtCeBtaKnF\ OhadQeenaSaKnYNFSathtMYMFFME" I decided by inspection that "Q" was probably "b" (I saw "been"). > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b"],Explode(Example_sub))); "RahFanRneEthetBNthMYthatBKChaBdhaddeGtBMOedtheaFFKanCethathadVM\ KnedtheFandGMYtheHKdFandGYMBthMNGandGMYOeaBGaGHMtheBCMnYeG\ GMBRahFanSBeGKdedMXeBtheCMNnCKFandthNGtheHKdFandGNndeBheBE\ atChaGHMtheBCMnYeGGMBtheHKdFandGhadYaFFentMBKChaBdaGFMBdBa\ hFMYdhaBaatFeaGttheFandGEhKChhadGMYaBGNBBendeBedtMhKHGheRn\ eEthebeneXMFenCeMYhKGaCtKMnGandtheneedYMBtheHbNtKtCeBtaKnF\ OhadbeenaSaKnYNFSathtMYMFFME" I got M = "o" by looking at the frequency table. > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b","M","o"],Explode(Example_sub))); "RahFanRneEthetBNthoYthatBKChaBdhaddeGtBoOedtheaFFKanCethathadVo\ KnedtheFandGoYtheHKdFandGYoBthoNGandGoYOeaBGaGHotheBConYeG\ GoBRahFanSBeGKdedoXeBtheCoNnCKFandthNGtheHKdFandGNndeBheBE\ atChaGHotheBConYeGGoBtheHKdFandGhadYaFFentoBKChaBdaGFoBdBa\ hFoYdhaBaatFeaGttheFandGEhKChhadGoYaBGNBBendeBedtohKHGheRn\ eEthebeneXoFenCeoYhKGaCtKonGandtheneedYoBtheHbNtKtCeBtaKnF\ OhadbeenaSaKnYNFSathtoYoFFoE" Y="f" came from my recognition of an instance of "of". > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b","M","o","Y","f"],Explode(Example_sub))); "RahFanRneEthetBNthofthatBKChaBdhaddeGtBoOedtheaFFKanCethathadVo\ KnedtheFandGoftheHKdFandGfoBthoNGandGofOeaBGaGHotheBConfeG\ GoBRahFanSBeGKdedoXeBtheCoNnCKFandthNGtheHKdFandGNndeBheBE\ atChaGHotheBConfeGGoBtheHKdFandGhadfaFFentoBKChaBdaGFoBdBa\ hFofdhaBaatFeaGttheFandGEhKChhadGofaBGNBBendeBedtohKHGheRn\ eEthebeneXoFenCeofhKGaCtKonGandtheneedfoBtheHbNtKtCeBtaKnF\ OhadbeenaSaKnfNFSathtofoFFoE" I recognized the word "for" and got B ="r". > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b","M","o","Y","f","B","r"],Explode(Example_sub))); "RahFanRneEthetrNthofthatrKChardhaddeGtroOedtheaFFKanCethathadVo\ KnedtheFandGoftheHKdFandGforthoNGandGofOearGaGHotherConfeG\ GorRahFanSreGKdedoXertheCoNnCKFandthNGtheHKdFandGNnderherE\ atChaGHotherConfeGGortheHKdFandGhadfaFFentorKChardaGFordra\ hFofdharaatFeaGttheFandGEhKChhadGofarGNrrenderedtohKHGheRn\ eEthebeneXoFenCeofhKGaCtKonGandtheneedfortheHbNtKtCertaKnF\ OhadbeenaSaKnfNFSathtofoFFoE" I got G = "s" and N = "u" by recognizing "surrendered". The rest of the deciphering is easy by word recognition. > Implode(partial_sub_cipher(["J","t","L","h","T","e","W","a","A","n","D","d","Q","b","M","o","Y","f","B","r","G","s","N","u"],Explode(Example_sub))); "RahFanRneEthetruthofthatrKChardhaddestroOedtheaFFKanCethathadVo\ KnedtheFandsoftheHKdFandsforthousandsofOearsasHotherConfes\ sorRahFanSresKdedoXertheCounCKFandthustheHKdFandsunderherE\ atChasHotherConfessortheHKdFandshadfaFFentorKChardasFordra\ hFofdharaatFeasttheFandsEhKChhadsofarsurrenderedtohKHsheRn\ eEthebeneXoFenCeofhKsaCtKonsandtheneedfortheHbutKtCertaKnF\ OhadbeenaSaKnfuFSathtofoFFoE" > > #self_count(trigrams(Explode(Example_Vigenere))); #I don't know why this is so slow. > > > #sort_frequency_table(%); YJK and YOJ are repeated, for example. We are now going to apply the Kasiski test: if we look at repeated trigram (or longer segments) it is likely that they represent the same text shifted by a multiple of the key length! To get these positions, we develop the following function: > # function which returns list of positions of an item in a list. > find := (item,list) ->if nops(list) = 0 then [] else if list[1]=item then [1,op(map ((x->x+1), > find(item,list[2..nops(list)])))] else map ((x->x+1),find(item,list[2..nops(list)])) end if end if; > > > find := proc(item, list) option operator, arrow; if nops(list) = 0 then [] else if list[1] = item then [1, op(map(x -> x + 1, find(item, list[2 .. nops(list)])))] else map(x -> x + 1, find(item, list[2 .. nops(list)])) end if end if end proc > find("a",Explode("hahaha")); [2, 4, 6] > find(["Y","J","K"],trigrams(Explode(Example_Vigenere))); [39, 191, 379, 395] > gcd(191-39,379-39);gcd(191-39,395-39); 4 4 > find(["Y","O","J"],trigrams(Explode(Example_Vigenere))); [157, 297, 369] > gcd(297-157,369-157); 4 The evidence of the Kasiski text strongly suggests that the length of the key is 4. > # I think the key length must be 4. > The sample_list function takes every nth element of a list starting with the (m mod n)th element. > sample_list:=(a,b,list)->if list = [] then [] else if a mod b = 1 then [list[1],op(sample_list(a-1,b,list[2..nops(list)]))] > else sample_list(a-1,b,list[2..nops(list)]) end if end if; sample_list := proc(a, b, list) option operator, arrow; if list = [] then [] else if a mod b = 1 then [list[1], op(sample_list(a - 1, b, list[2 .. nops(list)]))] else sample_list(a - 1, b, list[2 .. nops(list)]) end if end if end proc > sample_list(1,2,Explode("hahaha")); ["h", "h", "h"] > sample_list(2,2,Explode("hahaha")); ["a", "a", "a"] This is weird maple syntax for summing numbers in a list. > foldl(`+`,0,op([1,2,3,4])); 10 This computes "n choose 2". > choose2 := n -> (n*(n-1))/2; choose2 := n -> 1/2 n (n - 1) ioc stands for "index of coincidence" -- this one gets the i.o.c. from the list of frequencies. > ioc:= L -> evalf( foldl(`+`,0,op( map (choose2, L) ) ) / (choose2(foldl(`+`,0,op(L))) )); foldl(`+`, 0, op(map(choose2, L))) ioc := L -> evalf(----------------------------------) choose2(foldl(`+`, 0, op(L))) This generates a frequency table from a list then computes the i.o.c. > IOC := L -> ioc(sample_list(2,2,self_count(L))); IOC := L -> ioc(sample_list(2, 2, self_count(L))) Note that the substitution cipher example has the same IOC that we expect from English text. > IOC(Explode(Example_sub)); .06973338859 The IOC of the full Vigenere text is low. > IOC(Explode(Example_Vigenere)); .04342993445 Now our aim is to discover the key length by computing IOC of sampled text (every n letters). > IOC(sample_list(1,2,Explode(Example_Vigenere))); # key length 2 looks unlikely. .05114004405 > IOC(sample_list(1,3,Explode(Example_Vigenere))); # key length 3looks unlikely. .04337349398 > IOC(sample_list(1,4,Explode(Example_Vigenere))); .06593548387 > IOC(sample_list(2,4,Explode(Example_Vigenere))); .05795961185 > IOC(sample_list(3,4,Explode(Example_Vigenere))); .05782848151 > IOC(sample_list(4,4,Explode(Example_Vigenere))); .06045108838 > # the index of coincidence appears to confirm the conjecture that the key is of length 4. > > Alph := l -> Ord(l)-Ord("A"); Alph := l -> :-Ord(l) - :-Ord("A") > Alph("B"); 1 To find the displacement between letters in the key, we use the IOC again -- if we merge one of the 4 lists with another, shifting the second by a guessed difference between the two key letters, we will get a high IOC when we hit the right value! The following function implements this merger of a list with a second shifted list. > shiftmerge := (n,L,M) -> [op(map(Alph,L)),op(map(subs(N=n,(x->((Alph(x))+N) mod 26)) ,M))]; shiftmerge := (n, L, M) -> [op(map(Alph, L)), op(map(subs(N = n, x -> (Alph(x) + N) mod 26), M))] > > # using shiftmerge, I can use index of coincidence to determine shifts between letters of the key > # the four sublists follow. > L1 := sample_list(1,4,Explode(Example_Vigenere)); L1 := ["Z", "O", "K", "X", "Z", "T", "T", "N", "U", "A", "K", "Y", "T", "R", "U", "Z", "Y", "K", "U", "K", "J", "T", "G", "K", "X", "C", "L", "R", "G", "Q", "U", "K", "Z", "Y", "N", "U", "M", "G", "U", "Y", "G", "S", "L", "Z", "W", "T", "T", "A", "K", "G", "X", "Q", "X", "K", "Y", "O", "O", "G", "J", "A", "J", "Y", "K", "T", "J", "B", "O", "R", "J", "V", "T", "T", "O", "M", "Y", "Z", "N", "G", "Y", "R", "R", "K", "Q", "U", "T", "U", "T", "U", "J", "Z", "E", "Z", "Y", "R", "K", "K", "O", "C", "T", "K", "J", "G", "O", "H", "C", "E", "U", "K", "G", "K", "J", "S", "O", "Z", "R", "R", "Z", "T", "C", "U", "K", "K", "H", "X", "U"] > L2 := sample_list(2,4,Explode(Example_Vigenere)); L2 := ["O", "A", "Z", "L", "O", "S", "L", "V", "D", "W", "M", "A", "V", "H", "S", "L", "O", "K", "B", "J", "T", "P", "S", "J", "P", "H", "S", "H", "W", "V", "B", "F", "P", "I", "L", "R", "Y", "U", "S", "O", "K", "L", "P", "A", "B", "A", "L", "A", "S", "S", "S", "O", "B", "K", "M", "S", "A", "E", "L", "J", "O", "P", "Y", "K", "K", "L", "T", "M", "O", "H", "A", "A", "C", "P", "O", "L", "H", "Z", "P", "S", "H", "I", "L", "Y", "N", "T", "B", "Z", "V", "V", "A", "H", "O", "H", "K", "F", "S", "L", "K", "F", "U", "Y", "N", "H", "P", "V", "D", "Y", "Y", "A", "T", "H", "L", "P", "S", "L", "I", "N", "U", "S", "Y", "C", "L", "L"] > L3 := sample_list(3,4,Explode(Example_Vigenere)); L3 := ["J", "H", "B", "S", "J", "D", "X", "X", "J", "Y", "N", "S", "Z", "B", "Z", "J", "T", "Z", "W", "T", "T", "S", "Q", "F", "J", "X", "F", "S", "F", "K", "W", "W", "T", "Z", "Q", "J", "N", "I", "I", "J", "H", "Y", "L", "M", "J", "Z", "I", "Y", "T", "B", "T", "F", "N", "M", "F", "D", "M", "J", "G", "M", "N", "X", "X", "M", "W", "S", "X", "F", "N", "W", "X", "T", "N", "S", "J", "W", "Y", "G", "H", "D", "W", "F", "Y", "P", "K", "X", "U", "Z", "B", "U", "M", "C", "J", "N", "Y", "X", "Q", "I", "Y", "I", "Y", "J", "M", "H", "Y", "Z", "J", "N", "J", "T", "J", "D", "G", "B", "F", "F", "W", "I", "F", "I", "T", "N", "K", "N"] > L4:= sample_list(4,4,Explode(Example_Vigenere)); L4 := ["Y", "J", "G", "V", "Q", "Q", "Y", "J", "F", "J", "T", "Q", "V", "X", "P", "T", "Y", "R", "U", "P", "T", "I", "J", "T", "F", "C", "K", "F", "E", "L", "P", "C", "P", "V", "Q", "F", "O", "V", "W", "J", "Q", "Q", "J", "G", "G", "T", "Q", "J", "E", "C", "E", "F", "P", "K", "O", "Y", "V", "U", "C", "G", "U", "V", "C", "C", "K", "J", "G", "P", "U", "G", "K", "N", "P", "C", "N", "V", "Y", "C", "C", "C", "I", "U", "Y", "K", "T", "W", "V", "P", "P", "C", "G", "G", "E", "O", "J", "V", "Q", "C", "J", "K", "F", "H", "V", "M", "J", "J", "X", "F", "J", "N", "K", "F", "W", "K", "V", "U", "K", "Q", "U", "K", "H", "N", "Q", "F"] You should vary the first argument of the shiftmerge function until you get the right shift. The change in IOC is dramatic! > IOC(shiftmerge(25,L1,L2)); # 25? .06127736753 > IOC(shiftmerge(1,L1,L3)); # 4? .06292913590 > IOC(shiftmerge(4,L1,L4)); # 1? .06257287213 > Example_Vigenere; "ZOJYOAHJKZBGXLSVZOJQTSDQTLXYNVXJUDJFAWYJKMNTYASQTVZVRHBXUSZPZLJ\ TYOTYKKZRUBWUKJTPJTTTTPSIGSQJKJFTXPJFCHXCLSFKRHSFGWFEQVKLU\ BWPKFWCZPTPYIZVNLQQURJFMYNOGUIVUSIWYOJJGKHQSLYQLPLJZAMGWBJ\ GTAZTTLIQAAYJKSTEGSBCXSTEQOFFXBNPKKMKYMFOOSDYOAMVGEJUJLGCA\ JMGJONUYPXVKYXCTKMCJKWKBLSJOTXGRMFPJONUVHWGTAXKTATNOCNPMPS\ CYOJNZLWVNHYYGZGCYPHCRSDCRHWIKIFUQLYYUYPKTNKTUTXWTBUVUZZPJ\ VBPZVUCEAMGZHCGYOJERHNOKKYJKFXVOSQQCLICTKYJKFIKJUYFGYJHONM\ VHHHMCPYJEVZJUDJXKYNFGYJJKATNJTJKSHDFOLGWZPBKRSFVRLFUZIWKT\ NIQCUFUUSIKKYTHKCNNHLKQXLNFU" > > > keyguess1:= [0,26-25,26-1,26-4]; keyguess1 := [0, 1, 25, 22] > map(alphabetinv,(keyguess1)); ["A", "B", "Z", "W"] > LowerCase(Implode((map (alphabetinv,keyguess1)))); "abzw" > I used shiftdecipher to generate shifts because its output is lower case. I plugged in each number from 1 up to 20 for the first argument of shiftcipher until it came clean. > unvigenere(shiftdecipher(20,"ABZW"),LowerCase(Example_Vigenere)); "thewitcheswerenttheonlyoneswhoshowedupthefirstnonoutlawvoluntee\ rshowedupoursecondmorningallhecarriedwasaflailandapackofjo\ urneyrationsbuthelookedgrimandtoldushehadcometofighttheque\ enturnedoutthelocalwarlockhadruinedhisfamilywithtaxesdebau\ chedhissistersandhaddrivenhimselfandhisparentsintolivingin\ ashelterthatwasbasicallyalargebasketworkingfromsunuptosund\ owntopaythetaxesheclaimedtheystillowedandtheydidntdarefigh\ tbackwithyouhoweveridarehetoldmeimaydiebutiwillatleastbrin\ gdownasoldierofevilbeforeido" > shiftdecipher(20,"ABZW"); #this is the correct key. "ghfc" > > > > >