with(linalg): numbers:=proc(s) local alph,v,n,m,i,c; alph:=`abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ`; n:=length(s); v:=[]; for i from 1 to n do c:=substring(s,i..i); m:=searchtext(c,alph); if m > 0 then v:=[op(v), (m -1 mod 26) + 1] fi; od; RETURN(v) end: letters:=proc(v) local alph,i,msg; alph:=`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; msg:=``; for i from 1 to nops(v) do msg:=cat(msg,substring(alph,v[i]..v[i]) ); od; RETURN(msg); end: upcase:=w->letters(numbers(w)): caesar:=(plaintext,key)-> letters( map( (i,k)-> (i-1+k mod 26)+1 , numbers(plaintext), key)): tryall:= w -> matrix([[seq( caesar(w,k), k=1..13)],[seq( caesar(w,k), k=14..26)]]): affine:=(plaintext,key)-> letters( map( (i,k)-> (k[2]*(i+k[1])-1 mod 26)+1 , numbers(plaintext), key)): monoencode:=proc(plaintext,keyword) local i,v,ciphertext; v:=numbers(plaintext); ciphertext:=``; for i from 1 to nops(v) do ciphertext:=cat(ciphertext,substring(keyword,v[i]..v[i])): od; RETURN(ciphertext) end: monodecode:=proc(ciphertext,keyword) local i,j,alph,plaintext; alph:=`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; plaintext:=``; for i from 1 to length(ciphertext) do j:=searchtext(substring(ciphertext,i..i),keyword); plaintext:=cat(plaintext,substring(alph,j..j)): od; RETURN(plaintext) end: freq:=proc(msg) local alph,v,ans,x; alph:=`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; v:=sort(numbers(msg)); ans:=[]; for x from 1 to 26 do ans:=[op(ans), [substring(alph,x..x) , nops(select(has,v,x))] ]; od; RETURN(evalm(transpose(ans))); end: bigramfreq:=proc(msg) local v,ans,n,bigram,x,y; n:=length(msg); v:=sort([seq(substring(msg,x..(x+1)),x=1..(n-1))]); ans:=[]; bigram:=v[1]; y:=1; for x from 2 to n-1 do if v[x] = bigram then y:=y+1; continue; else ans:=[op(ans),[bigram,y]]; bigram:=v[x]; y:=1; fi; od; ans:=[op(ans),[bigram,y]]; RETURN(ans); end: percent:=proc(msg) local A,n,a1,a2; A:=freq(msg); n:=sum( A[2,k], k=1..26); a1:=row(A,1); a2:=map( (x,n)->evalf(100*x/n,4) , row(A,2), n); RETURN(evalm(transpose(concat(a1,a2)))) end: sortfreq:=proc(msg) local alph,v,ans,x; alph:=`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; v:=sort(numbers(msg)); ans:=[]; for x from 1 to 26 do ans:=[op(ans), [substring(alph,x..x) , nops(select(has,v,x))] ]; od; ans:=sort(ans,(x,y)->evalb(x[2]>y[2])); RETURN(evalm(transpose(ans))); end: sortpercent:=proc(msg) local A,n,a1,a2; A:=sortfreq(msg); n:=sum( A[2,k], k=1..26); a1:=row(A,1); a2:=map( (x,n)->evalf(100*x/n,4) , row(A,2), n); RETURN(evalm(transpose(concat(a1,a2)))) end: chart:=[[`A`,`B`,`C`,`D`,`E`,`F`,`G`,`H`,`I`,`J`,`K`,`L`,`M`, `N`,`O`,`P`,`Q`,`R`,`S`,`T`,`U`,`V`,`W`,`X`,`Y`,`Z`], [8.167,1.492,2.782,4.253,12.702,2.228,2.015,6.094,6.966,0.153,0.772,4.025, 2.406,6.749,7.507,1.929,0.095,5.987,6.327,9.056,2.758,0.978,2.360,0.150, 1.974,0.074]]: chart:= [seq( [ chart[1,x],chart[2,x] ], x=1..26)]: schart:= sort(chart, (x,y)->evalb(x[2]>y[2]) ): alphseq:=`ETAOINSHRDLCUMWFGYPBVKJXQZ`: analyze:=proc(ciphertext,keyword) local alph,plaintext,amat,r,x; alph:=`ABCDEFGHIJKLMNOPQRSTUVWXYZ`; plaintext:=monodecode(ciphertext,keyword); amat:=sortfreq(ciphertext); r:=[seq( monodecode(amat[1,x],keyword) , x=1..26)]; concat( [`plain`,`cipher`,`freq`], transpose(concat(r,row(amat,1),row(amat,2)))) end: