diff --git a/src/cipher_analytical_machine/caesar_analyzers.clj b/src/cipher_analytical_machine/caesar_analyzers.clj index 841dd17..4d71f06 100644 --- a/src/cipher_analytical_machine/caesar_analyzers.clj +++ b/src/cipher_analytical_machine/caesar_analyzers.clj @@ -1,5 +1,6 @@ (ns cipher-analytical-machine.caesar-analyzers (:require [cipher-analytical-machine.caesar :as caesar] + [clojure.string :as cs] [cipher-analytical-machine.cipher-analyzers :as ca]) (:gen-class)) @@ -12,23 +13,36 @@ (conj acc [key (caesar/decrypt-message ciphertext key symbols)])) '() keys))) +(defn get-all-scores + "For pairs (key, plaintext) finds scores and return list of pairs [key, score]." + [letter-frequences pairs] + (map (fn [[key text]] + [key (ca/chi-squared-statistic text letter-frequences)]) + pairs)) + +(defn get-min-score-pair + "For pairs (key, plaintext) finds scores and return list of pairs [key, score]." + [pairs] + (reduce + (fn [[key value] [new-key new-value]] + (if (> value new-value) [new-key new-value] + [key value])) + [0 Double/MAX_VALUE] + pairs)) + (defn get-key "To find the key with frequencies of letters." [ciphertext symbols letter-frequences] (->> (get-all-texts ciphertext symbols) - (map (fn [[key text]] - [key (ca/chi-squared-statistic text letter-frequences)])) - (reduce - (fn [[key value] [new-key new-value]] - (if (> value new-value) [new-key new-value] - [key value])) - [0 Double/MAX_VALUE]) + (get-all-scores letter-frequences) + (get-min-score-pair) (first))) (defn get-plaintext - "Return the plaintext from a ciphertext." + "Return the plaintext from a ciphertext. The function is case-insensitive." [ciphertext symbols letter-frequences] - (caesar/decrypt-message ciphertext - (get-key ciphertext symbols letter-frequences) - symbols)) + (let [ciphertext (cs/lower-case ciphertext)] + (caesar/decrypt-message ciphertext + (get-key ciphertext symbols letter-frequences) + symbols))) diff --git a/test/cipher_analytical_machine/caesar_analyzers_test.clj b/test/cipher_analytical_machine/caesar_analyzers_test.clj new file mode 100644 index 0000000..2a06d97 --- /dev/null +++ b/test/cipher_analytical_machine/caesar_analyzers_test.clj @@ -0,0 +1,76 @@ +(ns cipher-analytical-machine.caesar-analyzers-test + (:require + [clojure.test :refer :all] + [cipher-analytical-machine.caesar-analyzers :refer :all] + [cipher-analytical-machine.symbol-frequences :as sf] + [cipher-analytical-machine.cipher-analyzers :as ca] + [clojure.string :as cs])) + +(deftest get-all-texts-test + (testing "There're three text when the text is 'abc' and the set of symbol is 'abc'." + (is (= 3 (count (get-all-texts "abc" "abc"))))) + + (testing "A pair must have an integer and a string." + (let [pairs (get-all-texts "abc" "abc") + pair (first pairs)] + (is (and (int? (first pair)) + (string? (last pair)))))) + + (testing "There're 27 combinations for a 'Hello World'." + (let [ciphertext "khoorczruog" + symbols "abcdefghijklmnopqrstuvwxyz "] + (is (= 27 (count (get-all-texts ciphertext symbols))))))) + +(deftest get-all-scores-test + (testing "There're 27 combinations for a 'Hello World'." + (let [ciphertext "khoorczruog" + symbols "abcdefghijklmnopqrstuvwxyz " + frequences sf/english-letter-frequences + text-pairs (get-all-texts ciphertext symbols)] + (is (= 27 (count (get-all-scores frequences text-pairs))))))) + +(deftest get-min-score-pair-test + (testing "If a key is one, then the min score pair is 15." + (let [scores (list [0 20.0] [1 15.0] [2 30.0]) + min-score-pair (get-min-score-pair scores)] + (is (= [1 15.0] min-score-pair))))) + +(deftest get-key-test + (let [plaintext "hello world" + ciphertext "khoorczruog" + key 3 + symbols "abcdefghijklmnopqrstuvwxyz " + frequences sf/english-letter-frequences] + (testing "The plaintext is encrypted with 3 as the key." + (is (= key (get-key ciphertext symbols frequences))))) + + (let [; З поеми "Кавказ" Тараса Григоровича Шевченка: + plaintext "Борітеся – поборете, Вам Бог помагає! За вас правда, за вас слава. І воля святая!" + ciphertext "жхчощйшде–ецхжхчйщй,езєуежхиецхуєиєк!емєезєшецчєзїє,емєезєшештєзє.еоезхтдешздщєд!" + key 7 + symbols "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя " + frequences sf/ukrainian-letter-frequences] + (testing "The plaintext is encrypted with 3 as the key." + (is (= key (get-key ciphertext symbols frequences)))))) + +(deftest get-plaintext-test + (let [plaintext "hello world" + ciphertext "khoorczruog" + symbols "abcdefghijklmnopqrstuvwxyz " + frequences sf/english-letter-frequences] + (testing "The plaintext is encrypted with 3 as the key." + (is (= plaintext (get-plaintext ciphertext symbols frequences)))) + + (testing "The ciphertext is case-insensitive." + (is (= plaintext (get-plaintext "KhoorcZruog" symbols frequences))))) + + (let [; З поеми "Кавказ" Тараса Григоровича Шевченка: + plaintext "Борітеся – поборете, Вам Бог помагає! За вас правда, за вас слава. І воля святая!" + ciphertext "жхчощйшде–ецхжхчйщй,езєуежхиецхуєиєк!емєезєшецчєзїє,емєезєшештєзє.еоезхтдешздщєд!" + key 7 + symbols "абвгґдеєжзиіїйклмнопрстуфхцчшщьюя " + frequences sf/ukrainian-letter-frequences] + (testing "The ciphertext is case-insensitive." + (is (= (cs/lower-case plaintext) + (get-plaintext ciphertext symbols frequences)))))) +