Cryptography Assignment Solution
Cryptography Assignment Solution
> m := 30; m := 30 > numkeys := m*phi(m); numkeys := 240 > m := 100; m := 100 > numkeys := m*phi(m); numkeys := 4000 > m := 1225; m := 1225 > numkeys := m*phi(m); numkeys := 1029000
"inverse of 8 is 11" "inverse of 9 is 13" "inverse of 10 is 3" "inverse of 11 is 8" "inverse of 12 is 17" "inverse of 13 is 9" "inverse of 14 is 27" "inverse of 15 is 2" "inverse of 16 is 20" "inverse of 17 is 12" "inverse of 18 is 21" "inverse of 19 is 26" "inverse of 20 is 16" "inverse of 21 is 18" "inverse of 22 is 4" "inverse of 23 is 24" "inverse of 24 is 23" "inverse of 25 is 7" "inverse of 26 is 19" "inverse of 27 is 14" "inverse of 28 is 28" >
b) The following ciphertext was actually encrypted using the key so we use to decrypt it. > C:="ETEGENLMDNTNEOORDAHATECOESAHLRMI"; C := "ETEGENLMDNTNEOORDAHATECOESAHLRMI" > L:=[4,1,6,2,7,3,8,5]; L := [4, 1, 6, 2, 7, 3, 8, 5 ] > for i to 8 do pi[i]:=L[i] od: > m := 8; n := length(C); P:="": m := 8 n := 32 > for i to iquo(n,m) do for j to m do P := cat(P,C[m*(i-1)+pi[j]]) od od: > P; "GENTLEMENDONOTREADEACHOTHERSMAIL" Plaintext: Gentlemen do not read each others mail.
The Ciphertext: > C := "EMGLOSUDCGDNCUSWYSFHNSFCYKDPUMLWGYICOXYSIPJCK\ QPKUGKMGOLICGINCGACKSNISACYKZSCKXECJCKSHYSXCG\ OIDPKZCNKSHICGIWYGKKGKGOLDSILKGOIUSIGLEDSPWZU\ GFZCCNDGYYSFUSZCNXEOJNCGYEOWEUPXEZGACGNFGLKNS\ ACIGOIYCKXCJUCIUZCFZCCNDGYYSFEUEKUZCSOCFZCCNC\ IACZEJNCSHFZEJZEGMXCYHCJUMGKUCY"; C := "EMGLOSUDCGDNCUSWYSFHNSFCYKDPUMLWGYICOXYSIPJCKQPKUG \ KMGOLICGINCGACKSNISACYKZSCKXECJCKSHYSXCGOIDPKZCNKSHICGIW \ YGKKGKGOLDSILKGOIUSIGLEDSPWZUGFZCCNDGYYSFUSZCNXEOJNCGYE \
OWEUPXEZGACGNFGLKNSACIGOIYCKXCJUCIUZCFZCCNDGYYSFEUEKUZC \ SOCFZCCNCIACZEJNCSHFZEJZEGMXCYHCJUMGKUCY" > n := length(C); n := 256 > # Below, Freq will be single character frequency, Freq2 for digrams, Freq3 for trigrams > for i to n do Freq[C[i]] := 0 od: for i to n do Freq[C[i]] := Freq[C[i]] + 1 od: The most frequently occuring letters in sorted desending order: > sort(map(proc(x) if rhs(x)<9 then NULL else x fi end ,op(op(Freq))), (x,y)->rhs(x)>rhs(y)); ["C" = 37, "G" = 24, "S" = 20, "K" = 18, "I" = 15, "Y" = 15, "U" = 14, "N" = 13, "Z" = 13, "E" = 12, "O" = 10, "F" = 9 ] > for i to n-1 do Freq2[C[i..i+1]] := 0 od: for i to n-1 do Freq2[C[i..i+1]] := Freq2[C[i..i+1]] + 1 od: The most frequently occuring digrams in sorted desending order: > sort(map(proc(x) if rhs(x)<4 then NULL else x fi end ,op(op(Freq2))), (x,y)->rhs(x)>rhs(y)); ["ZC" = 7, "CG" = 7, "CK" = 5, "YS" = 5, "NC" = 5, "AC" = 5, "GO" = 5, "CN" = 5, "FZ" = 4, "CY" = 4, "GY" = 4, "SF" = 4, "GK" = 4 ] > for i to n-2 do Freq3[C[i..i+2]] := 0 od: for i to n-2 do Freq3[C[i..i+2]] := Freq3[C[i..i+2]] + 1 od: The most frequently occuring trigrams in sorted desending order: > sort(map(proc(x) if rhs(x)<2 then NULL else x fi end ,op(op(Freq3))), (x,y)->rhs(x)>rhs(y)); ["FZC" = 3, "GOI" = 3, "CCN" = 3, "YSF" = 3, "ZCC" = 3, "CGI" = 2, "GAC" = 2, "CYK" = 2, "KGO" = 2, "NCG" = 2, "ZCN" = 2, "ICG" = 2, "SAC" = 2, "GYY" = 2, "JCK" = 2, "KSH" = 2, "CND" = 2, "JNC" = 2, "DGY" = 2, "CFZ" = 2, "YYS" = 2, "NDG" = 2, "GOL" = 2, "UZC" = 2, "ZEJ" = 2, "CKS" = 2, "CKX" = 2, "CJU" = 2 ] > # from the Freq, the most frequent occuring character is C, so we suspect that # C decrypts to e, C->e # also, it is given that F->w > P := CharacterMap("FC","we",C); P := "EMGLOSUDeGDNeUSWYSwHNSweYKDPUMLWGYIeOXYSIPJeKQPKUGK \ MGOLIeGINeGAeKSNISAeYKZSeKXEeJeKSHYSXeGOIDPKZeNKSHIeGIWYGKKG \ KGOLDSILKGOIUSIGLEDSPWZUGwZeeNDGYYSwUSZeNXEOJNeGYEOWEUPX \ EZGAeGNwGLKNSAeIGOIYeKXeJUeIUZewZeeNDGYYSwEUEKUZeSOewZeeNeIA \ eZEJNeSHwZEJZEGMXeYHeJUMGKUeY" > # now C->e, F->w > # since both CN and NC are frequent, and ZCN, FZC are
> # since both CN and NC are frequent, and ZCN, FZC are frequent. # we know WHE is likely, so Z->h, and N->l, therefore ZCN->hel, FZC->whe > P := CharacterMap("FCZN","wehl",C); P := "EMGLOSUDeGDleUSWYSwHlSweYKDPUMLWGYIeOXYSIPJeKQPKUGKM \ GOLIeGIleGAeKSlISAeYKhSeKXEeJeKSHYSXeGOIDPKhelKSHIeGIWYGKKGKGO \ LDSILKGOIUSIGLEDSPWhUGwheelDGYYSwUShelXEOJleGYEOWEUPXEhGAeGl \ wGLKlSAeIGOIYeKXeJUeIUhewheelDGYYSwEUEKUheSOewheeleIAehEJleSHwhEJ \ hEGMXeYHeJUMGKUeY" > # now C->e, F->w, Z->h, N->l # only frequent trigram ending with ZC is UZC, and U is quite frequent, so # likely it is U->t, UZC->the > P := CharacterMap("FCZNU","wehlt",C); P := "EMGLOStDeGDletSWYSwHlSweYKDPtMLWGYIeOXYSIPJeKQPKtGKMGOLI \ eGIleGAeKSlISAeYKhSeKXEeJeKSHYSXeGOIDPKhelKSHIeGIWYGKKGKGOLDSI \ LKGOItSIGLEDSPWhtGwheelDGYYSwtShelXEOJleGYEOWEtPXEhGAeGlwGLKlS \ AeIGOIYeKXeJteIthewheelDGYYSwEtEKtheSOewheeleIAehEJleSHwhEJhEGMXeYH \ eJtMGKteY" > # G, Y, S are all quite frequent, and appears as GYYSw # guess that GYYSw->arrow # G->a, Y->r, S->o > P := CharacterMap("FCZNUGYS","wehltaro",C); P := "EMaLOotDeaDletoWrowHlowerKDPtMLWarIeOXroIPJeKQPKtaKMaOLIeaIleaA \ eKolIoAerKhoeKXEeJeKoHroXeaOIDPKhelKoHIeaIWraKKaKaOLDoILKaOItoIaLED \ oPWhtawheelDarrowtohelXEOJlearEOWEtPXEhaAealwaLKloAeIaOIreKXeJteIthewhee \ lDarrowEtEKtheoOewheeleIAehEJleoHwhEJhEaMXerHeJtMaKter" > > # we see wheelDarrow, which should be wheelbarrow, so D->b > P := CharacterMap("FCZNUGYSD","wehltarob",C); P := "EMaLOotbeabletoWrowHlowerKbPtMLWarIeOXroIPJeKQPKtaKMaOLIeaIleaAe \ KolIoAerKhoeKXEeJeKoHroXeaOIbPKhelKoHIeaIWraKKaKaOLboILKaOItoIaLEboP \ WhtawheelbarrowtohelXEOJlearEOWEtPXEhaAealwaLKloAeIaOIreKXeJteIthewheelba \ rrowEtEKtheoOewheeleIAehEJleoHwhEJhEaMXerHeJtMaKter" > # K is quite frequent, and GK, CK are frequent, so A-, E- are frequent # also I is quite frequent, but digrams are not frequent. # wheeleI is probably wheeled, so I->d > # guess that K->s, since Khoe is probably shoe > P := CharacterMap("FCZNUGYSDKI","wehltarobsd",C); P := "EMaLOotbeabletoWrowHlowersbPtMLWardeOXrodPJesQPstasMaOLdeadleaAes \ oldoAershoesXEeJesoHroXeaOdbPshelsoHdeadWrassasaOLbodLsaOdtodaLEboPWhta \
wheelbarrowtohelXEOJlearEOWEtPXEhaAealwaLsloAedaOdresXeJtedthewheelbarrow \ EtEstheoOewheeledAehEJleoHwhEJhEaMXerHeJtMaster" > # EtEs should probably be itis, so guess E->i # first word is iM, so guess M->m # oOe is probably one, so O->n > P := CharacterMap("FCZNUGYSDKIEMO","wehltarobsdimn",C); P := "imaLnotbeabletoWrowHlowersbPtmLWardenXrodPJesQPstasmanLdeadleaAesold \ oAershoesXieJesoHroXeandbPshelsoHdeadWrassasanLbodLsandtodaLiboPWhtawheel \ barrowtohelXinJlearinWitPXihaAealwaLsloAedandresXeJtedthewheelbarrowitistheonew \ heeledAehiJleoHwhiJhiamXerHeJtmaster" > # now it is easy to finish it off: # bPt is probably but, so P->u # Wrow is probably grow, so W->g # maL is probably may, so L->y > P := CharacterMap("FCZNUGYSDKIEMOPWL","wehltarobsdimnugy",C); P := "imaynotbeabletogrowHlowersbutmygardenXroduJesQustasmanydeadleaAesoldo \ AershoesXieJesoHroXeandbushelsoHdeadgrassasanybodysandtodayiboughtawheelbarro \ wtohelXinJlearingituXihaAealwaysloAedandresXeJtedthewheelbarrowitistheonewheeled \ AehiJleoHwhiJhiamXerHeJtmaster" > # Hlowers is probably flowers, so H->f # XroduJes is probably produces, so X->p, J->c # Qust is probably just, so Q->j # leaAes is probably leaves, so A->v > P := CharacterMap("FCZNUGYSDKIEMOPWLHXJQA","wehltarobsdimnugyfpcjv ",C); P := "imaynotbeabletogrowflowersbutmygardenproducesjustasmanydeadleavesoldovers \ hoespiecesofropeandbushelsofdeadgrassasanybodysandtodayiboughtawheelbarrowtohel \ pinclearingitupihavealwayslovedandrespectedthewheelbarrowitistheonewheeledvehicleo \ fwhichiamperfectmaster" The plaintext is as follows: "I may not be able to grow flowers, but my garden produces just as many dead leaves, old overshoes, pieces of rope, and bushels of dead grass as anybodys, and today I bought a wheelbarrow to help in clearing it up. I have always loved and respected the wheelbarrow. It is the one wheeled vehicle of which I am perfect master"; >
code[temp] := i; od: The cipher text y: > Y:="KCCPKBGUFDPHQTYAVINRRTMVGRKDNBVFDETDGILTXRGUD\ DKOTFMBPVGEGLTGCKQRACQCWDNAWCRXIZAKFTLEWRPTYC\ QKYVXCHKFTPONCQQRHJVAJUWETMCMSPKQDYHJVDAHCTRL\ SVSKCGCZQQDZXGSFRLSWCWSJTBHAFSIASPRJAHKJRJUMV\ GKMITZHFPDISPZLVLGWTFPLKKEBDPGCEBSHCTJRWXBAFS\ PEZQNRWXCVYCGAONWDDKACKAWBBIKFTIOVKCGGHJVLNHI\ FFSQESVYCLACNVRWBBIREPBBVFEXOSCDYGZWPFDTKFQIY\ CWHJVLNHIQIBTKHJVNPIST": Apply the Wolfe Friedman test, and compute the indices of coincidence to find m: > n := length(Y): L := 8: A := Matrix(L,L): for m to L do q := iquo(n,m,r); for i to m do y := cat(seq(Y[m*j+i],j=0..q)); freq := Array(0..25); N := length(y); for j to N do freq[code[y[j]]] := freq[code[y[j]]] + 1 od; A[m,i] := evalf(add(freq[j]*(freq[j]-1)/N/(N-1),j=0..25),3) od od: A; 0.0409 0 0 0 0 0 0 0 0.0385 0.0471 0 0 0 0 0 0 0.0559 0.0481 0.0483 0 0 0 0 0 0.0373 0.0427 0.0376 0.0491 0 0 0 0 0.0426 0.0430 0.0326 0.0353 0.0430 0 0 0 0.0627 0.0838 0.0494 0.0649 0.0429 0.0734 0 0 0.0306 0.0443 0.0434 0.0408 0.0443 0.0443 0.0408 0 0.0332 0.0407 0.0337 0.0407 0.0395 0.0453 0.0407 0.0546 It appears that m=6 has values closest to 0.065 Now, we try to find the key by calculating Mg values > m := 6; m := 6 Compute y1,y2,y3,...,y6 > q := iquo(n,m,r):
> q := iquo(n,m,r): for i to m do y[i] := cat(seq(Y[m*j+i],j=0..q)); od; y1 := "KGQNGVGGTGCQWAWQHNJEPJTKQFWAPJGHPWKCTAQVNCIVJFVNIV \ CPQJQJT" y2 := "CUTRRFIUFEKCCKRKKCVTKVRCDRSFRRKFZTEEJFNYWKKKVFYVRF \ DFIVIV" y3 := "CFYRKDLDMGQWRFPYFQAMQDLGZLJSJJMPLFBBRSRCDAFCLSCREE \ YDYLBN" y4 := "PDATDETDBLRDXTTVTQJCDASCXSTIAUIDVPDSWPWGDWTGNQLWPX \ GTCNTP" y5 := "KPVMNTXKPTANILYXPRUMYHVZGWBAHMTILLPHXEXAKBIGHEABB \ OZKWHKI" y6 := "BHIVBDROVGCAZECCOHWSHCSQSCHSKVZSGKGCBZCOABOHISCBB \ SWFHIHS" > p := [.082, .015, .028, .043, .127, .022, .020, .061, .070, .002, .008, .040, .024, .067, .075, .019, .001, .060, .063, .091, .028, .010, .023, .001, .020, .001]: > Mg := proc(x::string, g::integer) local i,f,n; n := length(x); f := Array(0..25); for i to n do f[code[x[i]]] := f[code[x[i]]] + 1 od; evalf(add(p[1+i]*f[i+g mod 26],i=0..25)/n,5); end: > for i to m do seq(j=evalf(Mg(y[i],j),3),j=0..25) od; 0 = 0.0316, 1 = 0.0358, 2 = 0.0646, 3 = 0.0389, 4 = 0.0338, 5 = 0.0420, 6 = 0.0367, 7 = 0.0311, 8 = 0.0422, 9 = 0.0460, 10 = 0.0252, 11 = 0.0338, 12 = 0.0383, 13 = 0.0422, 14 = 0.0381, 15 = 0.0463, 16 = 0.0361, 17 = 0.0401, 18 = 0.0422, 19 = 0.0334, 20 = 0.0303, 21 = 0.0393, 22 = 0.0434, 23 = 0.0344, 24 = 0.0415, 25 = 0.0335 0 = 0.0380, 1 = 0.0395, 2 = 0.0489, 3 = 0.0417, 4 = 0.0395, 5 = 0.0362, 6 = 0.0454, 7 = 0.0304, 8 = 0.0268, 9 = 0.0355, 10 = 0.0449, 11 = 0.0306, 12 = 0.0350, 13 = 0.0477, 14 = 0.0405, 15 = 0.0330, 16 = 0.0355, 17 = 0.0706, 18 = 0.0365, 19 = 0.0299, 20 = 0.0291, 21 = 0.0356, 22 = 0.0296, 23 = 0.0379, 24 = 0.0458, 25 = 0.0369 0 = 0.0351, 1 = 0.0365, 2 = 0.0335, 3 = 0.0379, 4 = 0.0355, 5 = 0.0414, 6 = 0.0276, 7 = 0.0380, 8 = 0.0338, 9 = 0.0421, 10 = 0.0412, 11 = 0.0455, 12 = 0.0401, 13 = 0.0429,
14 = 0.0365, 15 = 0.0316, 16 = 0.0349, 17 = 0.0391, 18 = 0.0424, 19 = 0.0314, 20 = 0.0391, 21 = 0.0327, 22 = 0.0348, 23 = 0.0435, 24 = 0.0587, 25 = 0.0451 0 = 0.0454, 1 = 0.0381, 2 = 0.0438, 3 = 0.0371, 4 = 0.0368, 5 = 0.0379, 6 = 0.0311, 7 = 0.0333, 8 = 0.0390, 9 = 0.0375, 10 = 0.0368, 11 = 0.0512, 12 = 0.0407, 13 = 0.0313, 14 = 0.0349, 15 = 0.0660, 16 = 0.0371, 17 = 0.0297, 18 = 0.0390, 19 = 0.0408, 20 = 0.0253, 21 = 0.0351, 22 = 0.0413, 23 = 0.0332, 24 = 0.0347, 25 = 0.0440 0 = 0.0403, 1 = 0.0333, 2 = 0.0344, 3 = 0.0396, 4 = 0.0449, 5 = 0.0336, 6 = 0.0430, 7 = 0.0460, 8 = 0.0468, 9 = 0.0342, 10 = 0.0345, 11 = 0.0359, 12 = 0.0342, 13 = 0.0350, 14 = 0.0335, 15 = 0.0442, 16 = 0.0340, 17 = 0.0358, 18 = 0.0351, 19 = 0.0558, 20 = 0.0409, 21 = 0.0353, 22 = 0.0434, 23 = 0.0445, 24 = 0.0306, 25 = 0.0320 0 = 0.0416, 1 = 0.0382, 2 = 0.0367, 3 = 0.0421, 4 = 0.0388, 5 = 0.0268, 6 = 0.0333, 7 = 0.0394, 8 = 0.0365, 9 = 0.0341, 10 = 0.0477, 11 = 0.0345, 12 = 0.0249, 13 = 0.0367, 14 = 0.0704, 15 = 0.0422, 16 = 0.0320, 17 = 0.0322, 18 = 0.0387, 19 = 0.0327, 20 = 0.0401, 21 = 0.0414, 22 = 0.0353, 23 = 0.0371, 24 = 0.0393, 25 = 0.0485 We can find the key from looking at how many we should shift to get a value that is closest to 0.0657 we guess that y1 was obtained from shifting two places, so K1 = 2, similarly, K2 = 17, K3 = 24, K4 = 15, K5 = 19, K6 = 14 > keyword := cat(char[2],char[17],char[24],char[15],char[19],char[14]); keyword := "CRYPTO" So the keyword is CRYPTO Now, we can decrypt the message: > decrypt := proc(Y,K) local n,m,y,k,i,x,c; n,m := length(Y),length(K); y := [seq(code[Y[i]],i=1..n)]; k := [seq(code[K[i]],i=1..m)]; c := 1; for i to n do x[i] := y[i]-k[c] mod 26; c := c+1; if c=7 then c:=1 fi; od; cat(seq(char[x[i]],i=1..n)); end: > decrypt(Y,keyword); "ILEARNEDHOWTOCALCULATETHEAMOUNTOFPAPERNEEDEDFORAROOM \ WHENIWASATSCHOOLYOUMULTIPLYTHESQUAREFOOTAGEOFTHEWALLS \ BYTHECUBICCONTENTSOFTHEFLOORANDCEILINGCOMBINEDANDDOUBLE \ ITYOUTHENALLOWHALFTHETOTALFOROPENINGSSUCHASWINDOWSANDD \
OORSTHENYOUALLOWTHEOTHERHALFFORMATCHINGTHEPATTERNTHEN \ YOUDOUBLETHEWHOLETHINGAGAINTOGIVEAMARGINOFERRORANDTHEN \ YOUORDERTHEPAPER" I learned how to calculate the amount of paper needed for a room when I was at school. You multiply the square footage of the walls by the cubic contents of the floor and ceiling combined, and double it. You then allow half the total for openings such as windows and doors. Then you allow the other half for matching the pattern. Then you double the whole thing again to give a margin of error, and then you order the paper.
O Canada! Terre de nos aieux. Ton Front est ceint, de fleurons glorieux. Car ton bras sait porter lepee, il sait porter lacroix. Ton histoire est un epopee, des plus brillants exploits. Et ta valeur, de foi trempee, protegera nos foyers et nos droits.
Now, we try to find the key by calculating Mg values > m := 6; m := 6 Compute y1,y2,y3,...,y6 > q := iquo(n,m,r): for i to m do y[i] := cat(seq(Y[m*j+i],j=0..q)); od; y1 := "BILEXKTKPYMDLEAMGBXXEUHFXTBGDXGHTVXMBBELVMUEWNY \ QEZYMAMTIMDAGHKX" y2 := "NHSRUAYVVLPLPSLALZWAHLTLLZJAHZJTUVYANLLWVHFSAUYPHF \ OPUOILVBYKYT" y3 := "VQSIMMATVAQFRERSEAISOKQERXSWAIITHRISLRHIYYSILHIZBECGM \ EPVWTIVHM" y4 := "SCKFBQVDROSSOBWADVCCSCOBRCIDVBWOKGRCHFWSFUFGSSTSC \ GDHEHSGDHSSGB" y5 := "NEKJGLFVJKCRYUXZFVGBNEKKFICVFKEERZESJFETJYMRWICICVEVL \ VUFVFYUGL" y6 := "SEYKYJBBYYGLGUMLJPJYMAMFDWBYJCAWQBMPMJYFCRGLMMCC \ MJMACLYLYRSUCR" > # Mg was defined above in part b) for i to m do seq(j=Mg(y[i],j),j=0..25) od; 0 = 0.040746, 1 = 0.035936, 2 = 0.033413, 3 = 0.034286, 4 = 0.045556, 5 = 0.037079, 6 = 0.039714, 7 = 0.034809, 8 = 0.046476, 9 = 0.034540, 10 = 0.036540, 11 = 0.035730, 12 = 0.044349, 13 = 0.035508, 14 = 0.028016, 15 = 0.040809, 16 = 0.042730, 17 = 0.033841, 18 = 0.034968, 19 = 0.060984, 20 = 0.041016, 21 = 0.032635, 22 = 0.033714, 23 = 0.045524, 24 = 0.034349, 25 = 0.037730 0 = 0.040822, 1 = 0.034935, 2 = 0.032710, 3 = 0.043919, 4 = 0.037323, 5 = 0.036645, 6 = 0.036839, 7 = 0.068064, 8 = 0.036871, 9 = 0.032564, 10 = 0.028419, 11 = 0.046758, 12 = 0.030742, 13 = 0.039177, 14 = 0.036581, 15 = 0.035806, 16 = 0.033661, 17 = 0.039306, 18 = 0.047919, 19 = 0.039726, 20 = 0.045355, 21 = 0.033548, 22 = 0.042274, 23 = 0.036064, 24 = 0.035516, 25 = 0.029452 0 = 0.052935, 1 = 0.035516, 2 = 0.030984, 3 = 0.037871, 4 = 0.061097, 5 = 0.036210, 6 = 0.030435, 7 = 0.036887, 8 = 0.045790, 9 = 0.028306, 10 = 0.033742, 11 = 0.035693, 12 = 0.038629, 13 = 0.039645, 14 = 0.044403, 15 = 0.044016, 16 = 0.038839, 17 = 0.041742, 18 = 0.034984, 19 = 0.038790, 20 = 0.037113, 21 = 0.034129,
22 = 0.034097, 23 = 0.036613, 24 = 0.035129, 25 = 0.037403 0 = 0.042016, 1 = 0.043226, 2 = 0.039935, 3 = 0.043484, 4 = 0.036532, 5 = 0.031758, 6 = 0.030548, 7 = 0.032484, 8 = 0.028500, 9 = 0.033419, 10 = 0.052435, 11 = 0.036258, 12 = 0.029564, 13 = 0.040226, 14 = 0.069193, 15 = 0.042871, 16 = 0.032855, 17 = 0.033613, 18 = 0.044774, 19 = 0.028984, 20 = 0.032710, 21 = 0.033871, 22 = 0.031726, 23 = 0.033887, 24 = 0.042968, 25 = 0.053161 0 = 0.037742, 1 = 0.042806, 2 = 0.048516, 3 = 0.035387, 4 = 0.042677, 5 = 0.038564, 6 = 0.041855, 7 = 0.035048, 8 = 0.032081, 9 = 0.034790, 10 = 0.035371, 11 = 0.035113, 12 = 0.033839, 13 = 0.046952, 14 = 0.035290, 15 = 0.028548, 16 = 0.040177, 17 = 0.063193, 18 = 0.041790, 19 = 0.033613, 20 = 0.037919, 21 = 0.037613, 22 = 0.030823, 23 = 0.038371, 24 = 0.042419, 25 = 0.030500 0 = 0.029210, 1 = 0.034468, 2 = 0.036145, 3 = 0.027258, 4 = 0.037290, 5 = 0.048871, 6 = 0.033952, 7 = 0.040548, 8 = 0.043758, 9 = 0.045145, 10 = 0.038226, 11 = 0.039871, 12 = 0.034774, 13 = 0.037629, 14 = 0.033548, 15 = 0.027887, 16 = 0.039532, 17 = 0.036629, 18 = 0.040290, 19 = 0.038629, 20 = 0.053500, 21 = 0.036935, 22 = 0.033403, 23 = 0.035693, 24 = 0.064548, 25 = 0.033258 From the above result closest to 0.0657, we see that K1 = 19, K2 = 7, K3 = 4, K4 = 14, K5 = 17, K6 = 24 > keyword := cat(char[19],char[7],char[4],char[14],char[17],char[24]); keyword := "THEORY" So the keyword is THEORY Now, we can decrypt the message: > # decrypt was defined in part b) decrypt(Y,keyword); "IGREWUPAMONGSLOWTALKERSMENINPARTICULARWHODROPPEDWORD \ SAFEWATATIMELIKEBEANSINAHILLANDWHENIGOTTOMINNEAPOLISWHER \ EPEOPLETOOKALAKEWOBEGONCOMMATOMEANTHEENDOFASTORYICOU \ LDNTSPEAKAWHOLESENTENCEINCOMPANYANDWASCONSIDEREDNOTTO \ OBRIGHTSOIENROLLEDINASPEECHCOURSETAUGHTBYORVILLESANDTHEF \ OUNDEROFREFLEXIVERELAXOLOGYASELFHYPNOTICTECHNIQUETHATEN \ ABLEDAPERSONTOSPEAKUPTOTHREEHUNDREDWORDSPERMINUTE" The plaintext is as follows: I grew up among slow talkers, men in particular, who dropped words a few at a time like beans in a hill, and when I got to Minneapolis where people took a Lake Wobegon comma to mean the end of a story, I couldnt speak a whole sentence in company and was considered not too bright. So I enrolled in a speech course taught by Orville Sand, the founder of reflexive relaxology, a self-hypnotic technique that enabled a person to speak up to three hundred words per minute.
VRVPRTULHDNQWTWDTYGBPHXTFALJHASVBFXNGLLCHR\ ZBWELEKMSJIKNBHWRJGNMGJSGLXFEYPHAGNRBIEQJT\ AMRVLCRREMNDGLXRRIMGNSNRWCHRQHAEYEVTAQEBBI\ PEEWEVKAKOEWADREMXMTBHHCHRTKDNVRZCHRCLQOHP\ WQAIIWXNRMGWOIIFKEE": > n := length(Y); n := 313 > m := 5; m := 5 Compute y2, i.e. row 2 > q := iquo(n,m,r): y[2] := cat(seq(Y[m*j+2],j=0..q)); y2 := "HOEITESEWOOEGMFTIFUDSTNSNVTNDPASNHESBGSEGEMRDRSHEAIEOR \ THNHOANOE" > # Mg was defined in question 1.21 part b) seq(evalf(Mg(y[2],j),2),j=0..25); 0.069, 0.044, 0.032, 0.035, 0.044, 0.034, 0.036, 0.033, 0.029, 0.031, 0.042, 0.045, 0.040, 0.045, 0.046, 0.042, 0.037, 0.032, 0.034, 0.037, 0.032, 0.034, 0.043, 0.032, 0.026, 0.047 >
Next, we want to show that N(p 2 ) = p 4 (p 2 1 ) (p 2 p ), (10 marks) or more generally, N(p k ) = p (p 2 1 ) (p 2 p ) Let Mn denote the set of 2 x 2 matrices over Zn For each 2 k, define the function fk as follows: fk : M (k 1 ) x Mp -> M k
p p (4 (k 1 ))
fk(A, B ) = p A + B, where A is a 2 x 2 matrix over Zp , B is a 2 x 2 matrix over Zp First, we show that fk is a bijection. Suppose fk(A, B ) = fk(AA, BB), then p A + B = p AA + BB we can rewrite as p (A AA) = BB B.
(k 1 )
we can rewrite as p (A AA) = BB B. In other words, p divides each element of BB B, but BB B is a matrix over Zp, so BB B = 0, i.e. BB = B Now, p (A AA) = 0, so p divides each element of A AA, but A AA is a matrix over Zp , so A = AA Therefore, fk is injective. Also, the domain and codomain of fk have the same cardinality, so fk is a bijection. Second, we show that fk(A, B ) is invertible over Zp k iff B is invertible over Zp. Recall that a matrix C over Zp k is invertible iff det(C) is invertible over Zp k, i.e. gcd(det(C), p k) = 1 In other words, C is invertible over Zp k iff det(C) mod p <> 0 We can simply compute the determinant mod p: det(fk(A, B )) = det(p A + B) = det(B) (mod p) It is now easy to show that fk(A, B ) is invertible over Zp k iff B is invertible over Zp. From the bijection, we know that every matrix C over Zp k can be uniquely decomposed into matrices A, B such that A is a 2 x 2 matrix over Zp , B is a 2 x 2 matrix over Zp and C = p A + B. Furthermore, C is invertible over Zp k iff B is invertible over Zp. Now, we can count the number of invertible 2 x 2 matrices C over Zp k: We already know that the number of invertible matrices B over Zp is (p 2 1 ) (p 2 p ) A can be any matrix over Zp Therefore, N(p k ) = p
(4 (k 1 )) (k 1 ) (k 1 ) (k 1 ) (k 1 )
, so there are p
(4 (k 1 ))
of them.
(p 2 1 ) (p 2 p )
Finally, we want to show that N(p q ) = N(p ) N(q ) for primes p,q (5 marks) More generally, N(a b ) = N(a ) N(b ) for any a,b where a,b are relatively prime This time, we can also define a function g where g : Ma x Mb --> Ma b g(A, B ) = b A + a B, where A is a 2 x 2 matrix over Za, B is a 2 x 2 matrix over Zb It is not hard to show that g is a bijection with the property that g(A, B ) is invertible over Za b iff both A and B are invertible over Za and Zb respectively. (similar to arguments used in the chinese remainder theorem) Therefore, N(a b ) = N(a ) N(b ) Below is a small program that would compute N(n) for any n > N := proc(n) local F,g,p,k; g := (p,k)->(p^2-1)*(p^2-p)*p^(4*(k-1)); F := ifactors(n)[2]; mul(g(F[i][1],F[i][2]),i=1..nops(F));
mul(g(F[i][1],F[i][2]),i=1..nops(F)); end: > n := 6; n := 6 > N(n); 288 > n:=9; n := 9 > N(n); 3888 > n:=26; n := 26 > N(n); 157248 These correspond to the answers for question 1.13 >