From 2ae0efd5131f6b9762a8b14ad237d92c991a7f9d Mon Sep 17 00:00:00 2001 From: "Jake W. Ireland" Date: Tue, 9 Mar 2021 13:18:01 +1300 Subject: [PATCH 1/5] Type-error bug fix for monoalphabetic (fixes #28) --- src/monoalphabetic.jl | 107 +++++++++++++++++++++-------------------- test/monoalphabetic.jl | 6 +++ 2 files changed, 60 insertions(+), 53 deletions(-) diff --git a/src/monoalphabetic.jl b/src/monoalphabetic.jl index b7c603b..a51ad39 100644 --- a/src/monoalphabetic.jl +++ b/src/monoalphabetic.jl @@ -2,6 +2,7 @@ _keystr_to_dict(keystr::AbstractString) = Dict{Char, Char}(Char(i + 64) => c for (i, c) in enumerate(uppercase(keystr))) _keystr_to_dict(A::AbstractString, B::AbstractString) = Dict{eltype(A), eltype(B)}(a => b for (a, b) in zip(uppercase(A), uppercase(B))) # policy decision: all dictionaries are uppercase + Base.reverse(D::Dict{T, S}) where {T, S} = Dict{S, T}(reverse(p) for p in D) _monoalphabetic_substitution(text, sub_dict::Dict{T, S}) where {T, S} = @@ -125,7 +126,7 @@ function swap_two(str) indices = rand(1:length(str), 2) end - return join(Integer[i == indices[1] ? str[indices[2]] : (i == indices[2] ? str[indices[1]] : str[i]) for i in 1:length(str)]) + return join(Char[i == indices[1] ? str[indices[2]] : (i == indices[2] ? str[indices[1]] : str[i]) for i in 1:length(str)]) end """ @@ -171,10 +172,10 @@ julia> crack_monoalphabetic(str, chatty=0, rounds=10) """ function crack_monoalphabetic( ciphertext; - starting_key::AbstractString = "", - min_temp::AbstractFloat = 0.0001, - temp_factor::AbstractFloat = 0.97, - acceptance_prob::AbstractFloat = ((e,ep,t) -> ep > e ? 1. : exp(-(e-ep)/t)), + starting_key::AbstractString = string(), + min_temp::Union{AbstractFloat, Integer} = 0.0001, + temp_factor::Union{AbstractFloat, Integer} = 0.97, + acceptance_prob::Function = ((e,ep,t) -> ep > e ? 1. : exp(-(e-ep)/t)), chatty::Integer = 0, rounds::Integer = 1 ) @@ -198,64 +199,64 @@ function crack_monoalphabetic( key = join(start_key) else key = starting_key - end + end + + if chatty > 1 + println("Starting key: $(key)") + end - if chatty > 1 - println("Starting key: $(key)") - end + stripped_ciphertext = letters_only(ciphertext) + fitness = string_fitness(decrypt_monoalphabetic(stripped_ciphertext, key)) + total_best_fitness, total_best_key = fitness, key + total_best_decrypt = decrypt_monoalphabetic(ciphertext, key) - stripped_ciphertext = letters_only(ciphertext) - fitness = string_fitness(decrypt_monoalphabetic(stripped_ciphertext, key)) - total_best_fitness, total_best_key = fitness, key - total_best_decrypt = decrypt_monoalphabetic(ciphertext, key) - - for roundcount in 1:rounds - temp = 10^((roundcount - 1) / rounds) - while temp > min_temp - for i in 1:round(Int, min(ceil(1 / temp), 10)) - neighbour = swap_two(key) - new_fitness = string_fitness(decrypt_monoalphabetic(stripped_ciphertext, neighbour), alreadystripped = true) - if new_fitness > total_best_fitness - total_best_fitness = new_fitness - total_best_key = neighbour - total_best_decrypt = decrypt_monoalphabetic(ciphertext, total_best_key) - end - - threshold = rand() - - if chatty >= 2 - println("Current fitness: $(fitness)") - println("New fitness: $(new_fitness)") - println("Acceptance probability: $(acceptance_prob(fitness, new_fitness, temp))") - println("Threshold: $(threshold)") - end - - if acceptance_prob(fitness, new_fitness, temp) >= threshold - if chatty >= 1 - println("$(key) -> $(neighbour), threshold $(threshold), temperature $(temp), fitness $(new_fitness), prob $(acceptance_prob(fitness, new_fitness, temp))") - end - fitness = new_fitness - key = neighbour - end + for roundcount in 1:rounds + temp = 10^((roundcount - 1) / rounds) + while temp > min_temp + for i in 1:round(Int, min(ceil(1 / temp), 10)) + neighbour = swap_two(key) + new_fitness = string_fitness(decrypt_monoalphabetic(stripped_ciphertext, neighbour), alreadystripped = true) + if new_fitness > total_best_fitness + total_best_fitness = new_fitness + total_best_key = neighbour + total_best_decrypt = decrypt_monoalphabetic(ciphertext, total_best_key) end - - temp = temp * temp_factor + + threshold = rand() if chatty >= 2 - println("----") + println("Current fitness: $(fitness)") + println("New fitness: $(new_fitness)") + println("Acceptance probability: $(acceptance_prob(fitness, new_fitness, temp))") + println("Threshold: $(threshold)") + end + + if acceptance_prob(fitness, new_fitness, temp) >= threshold + if chatty >= 1 + println("$(key) -> $(neighbour), threshold $(threshold), temperature $(temp), fitness $(new_fitness), prob $(acceptance_prob(fitness, new_fitness, temp))") + end + fitness = new_fitness + key = neighbour end end - key, fitness = total_best_key, total_best_fitness - temp = 1 + temp = temp * temp_factor + + if chatty >= 2 + println("----") + end end - if chatty >= 1 - println("Best was $(total_best_key) at $(total_best_fitness)") - println(total_best_decrypt) - end - - return decrypt_monoalphabetic(ciphertext, key), key + key, fitness = total_best_key, total_best_fitness + temp = 1 + end + + if chatty >= 1 + println("Best was $(total_best_key) at $(total_best_fitness)") + println(total_best_decrypt) + end + + return decrypt_monoalphabetic(ciphertext, key), key end """ diff --git a/test/monoalphabetic.jl b/test/monoalphabetic.jl index 7686e65..33c0f44 100644 --- a/test/monoalphabetic.jl +++ b/test/monoalphabetic.jl @@ -31,3 +31,9 @@ @test decrypt_monoalphabetic("PCSSI EPHL HL JSKHYECUE", "qwertyuiopasdfghjklzxcvbnm", "abcdefghijklmnopqrstuvwxyz"; reverse_dict = false) == "jvllh cjps ps qlrpfcvgc" @test decrypt_monoalphabetic("PCSSI EPHL HL JSKHYECUE", "qwertyuiopasdfghjklzxcvbnm", "abcdefghijklmnopqrstuvwxyz"; reverse_dict = true) == "hello this is plaintext" @test decrypt_monoalphabetic("ITSSG ZIOL OL HSQOFZTBZ", "abcdefghijklmnopqrstuvwxyz", "qwertyuiopasdfghjklzxcvbnm"; reverse_dict = false) != decrypt_monoalphabetic("ITSSG ZIOL OL HSQOFZTBZ", "abcdefghijklmnopqrstuvwxyz", "qwertyuiopasdfghjklzxcvbnm"; reverse_dict = true) + +@test ( + RID = encrypt_monoalphabetic("hello there", "mnbvcxzlkjhgfdsapoiuytrewq"); + crack_monoalphabetic(RID) == ("gessi ngere", "INZYCDLPSFVKAUMJHOGRBTEQXW") + crack_monoalphabetic("93ee90299") == ("93ee90299", "XQJFEPHRBLTNKDCWVGAZMSIYOU") + ) From 2431d3c0f7086c0973f2d8e53b3dc70b1a41f8f0 Mon Sep 17 00:00:00 2001 From: "Jake W. Ireland" Date: Tue, 9 Mar 2021 13:33:24 +1300 Subject: [PATCH 2/5] Fixed syntax error --- test/monoalphabetic.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/monoalphabetic.jl b/test/monoalphabetic.jl index 33c0f44..3547771 100644 --- a/test/monoalphabetic.jl +++ b/test/monoalphabetic.jl @@ -34,6 +34,6 @@ @test ( RID = encrypt_monoalphabetic("hello there", "mnbvcxzlkjhgfdsapoiuytrewq"); - crack_monoalphabetic(RID) == ("gessi ngere", "INZYCDLPSFVKAUMJHOGRBTEQXW") - crack_monoalphabetic("93ee90299") == ("93ee90299", "XQJFEPHRBLTNKDCWVGAZMSIYOU") + crack_monoalphabetic(RID) == ("gessi ngere", "INZYCDLPSFVKAUMJHOGRBTEQXW"); + crack_monoalphabetic("93ee90299") == ("93ee90299", "XQJFEPHRBLTNKDCWVGAZMSIYOU"); ) From e419823c47e504dcd582eecc453a38456beef311 Mon Sep 17 00:00:00 2001 From: Smaug123 Date: Tue, 9 Mar 2021 19:25:01 +0000 Subject: [PATCH 3/5] Remove x86 workflow --- .github/workflows/CI.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index c9aa2b9..2ab2f87 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -24,13 +24,6 @@ jobs: - windows-latest arch: - x64 - - x86 - exclude: - # Test 32-bit only on Linux - - os: macOS-latest - arch: x86 - - os: windows-latest - arch: x86 include: # Add a 1.3 job because that's what Invenia actually uses - os: ubuntu-latest From 48b986af11b4c473fa3da6ff875ed98e1f3a9849 Mon Sep 17 00:00:00 2001 From: "Jake W. Ireland" Date: Wed, 10 Mar 2021 11:28:08 +1300 Subject: [PATCH 4/5] Updated version number --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index a6041a1..22e156f 100644 --- a/Project.toml +++ b/Project.toml @@ -1,6 +1,6 @@ name = "ClassicalCiphers" uuid = "ecf26e93-935c-5e64-9b21-bc8ac81b4723" -version = "2.1.0" +version = "2.1.1" [deps] LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" From cc144fa165b0baa0f24ee014553f9c07f499bccd Mon Sep 17 00:00:00 2001 From: "Jake W. Ireland" Date: Wed, 10 Mar 2021 11:32:57 +1300 Subject: [PATCH 5/5] Added chatty crack_monoalphabetic test for code coverage goal --- test/monoalphabetic.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/monoalphabetic.jl b/test/monoalphabetic.jl index 3547771..9c2ce85 100644 --- a/test/monoalphabetic.jl +++ b/test/monoalphabetic.jl @@ -36,4 +36,5 @@ RID = encrypt_monoalphabetic("hello there", "mnbvcxzlkjhgfdsapoiuytrewq"); crack_monoalphabetic(RID) == ("gessi ngere", "INZYCDLPSFVKAUMJHOGRBTEQXW"); crack_monoalphabetic("93ee90299") == ("93ee90299", "XQJFEPHRBLTNKDCWVGAZMSIYOU"); + crack_monoalphabetic("93ee90299"; chatty = 2) == ("93ee90299", "XQJFEPHRBLTNKDCWVGAZMSIYOU"); # for code coverage reasons! )