function [] = decrypt(trainingfilename, cipherfilename) % DECRYPT(TRAININGFILENAME, CIPHERFILENAME): print decryption of file % CIPHERFILENAME using file TRAININGFILENAME as training text % example 1: decrypt('genesis.txt', 'cryptannounce.txt') % example 2: decrypt('oldannounce.txt','scramble.txt') tic % time how long it takes to read files [traintot, whocares, trainbi] = tally(fopen(trainingfilename)); [ciphertot, whocares, cipherbi] = tally(fopen(cipherfilename)); cipheralpha = [' ' char('a'+0:'z'+0)]; % labels for cipher bigram table toc tic % time how long it takes to crack substitution cipher % search: keep looking as long as improvements are made % for each position i % search for position j such that "swap i&j" yields the best table % commit "swap i&j" d = distance(trainbi, cipherbi); % current distance go = 1; % whether to keep looking == "were any improvements made?" while go go = 0; % assume no improvements made for i = 2:27 % search for best j bestd = inf; % best distance so far use = []; % indices for best swap so far for j = 2:27 bi = cipherbi; bi(:,[i j]) = bi(:,[j i]); bi([i j],:) = bi([j i],:); testd = distance(bi, trainbi); if testd < bestd, bestd = testd; use = [i j]; end end % if made an improvement, update GO and commit "swap i&j" if bestd%c; distance %6.4f; labels %s\n', ... cipheralpha(use),bestd, cipheralpha); cipheralpha(use) = cipheralpha(esu); cipherbi(:,use)=cipherbi(:,esu); cipherbi(use,:)=cipherbi(esu,:); end end end toc % "compute" and print decryption key with no spaces bottom = char('a'+0:'z'+0); top = cipheralpha; top(1) = []; % throw out space disp('decryption key:') disp(top); disp(bottom); disp(''); % decrypt ciphertext transform(top, bottom, cipherfilename, 10) function d = distance(a,b) % D = DISTANCE(A,B): return L1 distance D between equal-sized matrices A, B d = sum(sum(abs(a-b)));