mirror of
https://github.com/Smaug123/ClassicalCiphers.jl
synced 2025-10-06 18:08:46 +00:00
Move to Project.toml, bump to Julia v1 (#18)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
*.jl.cov
|
||||
*.jl.*.cov
|
||||
*.jl.mem
|
||||
Manifest.toml
|
||||
.vscode/*
|
||||
|
@@ -2,10 +2,9 @@
|
||||
language: julia
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
julia:
|
||||
- 0.5
|
||||
- 0.6
|
||||
- 1.0
|
||||
- 1.1
|
||||
- nightly
|
||||
notifications:
|
||||
email: false
|
||||
|
15
Project.toml
Normal file
15
Project.toml
Normal file
@@ -0,0 +1,15 @@
|
||||
name = "ClassicalCiphers"
|
||||
uuid = "ecf26e93-935c-5e64-9b21-bc8ac81b4723"
|
||||
|
||||
[deps]
|
||||
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
|
||||
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
|
||||
|
||||
[compat]
|
||||
julia = "≥ 1.0.0"
|
||||
|
||||
[extras]
|
||||
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
|
||||
|
||||
[targets]
|
||||
test = ["Test"]
|
@@ -2,8 +2,6 @@ module ClassicalCiphers
|
||||
|
||||
# Monoalphabetic
|
||||
|
||||
using Compat
|
||||
|
||||
include("common.jl")
|
||||
include("monoalphabetic.jl")
|
||||
include("caesar.jl")
|
||||
|
@@ -1,5 +1,3 @@
|
||||
using Iterators
|
||||
|
||||
"""
|
||||
Encrypts the given plaintext according to the Affine cipher.
|
||||
The key is given as a pair of integers: first the multiplier, then
|
||||
@@ -42,6 +40,26 @@ function decrypt_affine(ciphertext, mult::Integer, add::Integer; offset=0)
|
||||
decrypt_monoalphabetic(ciphertext, keystr)
|
||||
end
|
||||
|
||||
function max_by(arr, f)
|
||||
currMax = undef
|
||||
currAns = undef
|
||||
set = false
|
||||
for i in arr
|
||||
if set == false
|
||||
set = true
|
||||
currMax = f(i)
|
||||
currAns = i
|
||||
else
|
||||
t = f(i)
|
||||
if currMax < t
|
||||
currMax = t
|
||||
currAns = i
|
||||
end
|
||||
end
|
||||
end
|
||||
currAns
|
||||
end
|
||||
|
||||
"""
|
||||
Cracks the given ciphertext according to the Affine cipher.
|
||||
Returns ((multiplier, additive constant), decrypted string).
|
||||
@@ -51,15 +69,11 @@ Converts the input to lowercase, but retains symbols.
|
||||
Optional arguments: mult=0, which specifies the multiplier if known;
|
||||
add=-1, which specifies the additive constant if known.
|
||||
"""
|
||||
function crack_affine(ciphertext; mult=0, add=-1)
|
||||
function crack_affine(ciphertext::AbstractString; mult=0, add=-1)
|
||||
mults = mult != 0 ? [mult] : [i for i in filter(x -> (x % 2 != 0 && x % 13 != 0), 1:25)]
|
||||
adds = add != -1 ? [add] : (0:25)
|
||||
|
||||
possible_keys = product(mults, adds)
|
||||
possible_keys = Iterators.product(mults, adds)
|
||||
|
||||
decrypts = [(i, decrypt_affine(ciphertext, i[1], i[2])) for i in possible_keys]
|
||||
|
||||
sort!(decrypts, by=(x -> string_fitness(x[2])))
|
||||
|
||||
reverse(decrypts[end])
|
||||
reverse(max_by([(i, decrypt_affine(ciphertext, i[1], i[2])) for i in possible_keys], x -> string_fitness(x[2])))
|
||||
end
|
@@ -5,7 +5,7 @@ so encrypt_caesar("abc", 1) == "BCD".
|
||||
|
||||
Converts the input to uppercase.
|
||||
"""
|
||||
function encrypt_caesar(plaintext, key::Integer)
|
||||
function encrypt_caesar(plaintext, key::T) where {T<:Integer}
|
||||
# plaintext: string; key: integer offset, so k=1 sends "a" to "b"
|
||||
key = ((key-1) % 26) + 1
|
||||
keystr = join([collect(Char(97+key):'z'); collect('a':Char(97+key-1))])
|
||||
|
@@ -29,10 +29,6 @@ function rotateRightStr(st::AbstractString, n)
|
||||
join(rotateRight(split(st, ""), n), "")
|
||||
end
|
||||
|
||||
flatten{T}(a::Array{T,1}) = any(x->isa(x,Array),a)? flatten(vcat(map(flatten,a)...)): a
|
||||
flatten{T}(a::Array{T}) = reshape(a,prod(size(a)))
|
||||
flatten(a)=a
|
||||
|
||||
function splitBy(arr, func)
|
||||
# implementation of the Mathematica function SplitBy
|
||||
# splits the array into sublists so that each list has the same value of func
|
||||
@@ -58,7 +54,7 @@ function get_trigram_fitnesses()
|
||||
|
||||
for l in lines
|
||||
(ngram, fitness) = split(l)
|
||||
dict[ngram] = parse(fitness)
|
||||
dict[ngram] = parse(Int32, fitness)
|
||||
end
|
||||
|
||||
close(f)
|
||||
@@ -72,7 +68,7 @@ Performs a trigram analysis on the input string, to determine how close it
|
||||
is to English. That is, splits the input string into groups of three letters,
|
||||
and assigns a score based on the frequency of the trigrams in true English.
|
||||
"""
|
||||
function string_fitness(input; alreadystripped=false)
|
||||
function string_fitness(input::AbstractString; alreadystripped=false)
|
||||
if !alreadystripped
|
||||
str = letters_only(input)
|
||||
else
|
||||
|
@@ -72,15 +72,15 @@ Ring is a string - for example, "AAA" - being the offset applied to each rotor.
|
||||
"AAA", for example, signifies no offset. The string must be three letters.
|
||||
skip_stecker_check=false, which when `true` skips validation of stecker settings.
|
||||
"""
|
||||
function encrypt_enigma{I <: Integer}(plaintext,
|
||||
rotors::Array{I, 1}, key::AbstractString;
|
||||
reflector_id='B', ring::AbstractString = "AAA",
|
||||
stecker = Tuple{Char, Char}[],
|
||||
skip_stecker_check = false)
|
||||
function encrypt_enigma(plaintext,
|
||||
rotors::Array{T, 1}, key::AbstractString;
|
||||
reflector_id='B', ring::AbstractString = "AAA",
|
||||
stecker = Tuple{Char, Char}[],
|
||||
skip_stecker_check = false) where {T<:Integer}
|
||||
parsed_stecker = parse_stecker(stecker)
|
||||
# validate stecker settings
|
||||
if !skip_stecker_check
|
||||
if flatten(parsed_stecker) != unique(flatten(parsed_stecker))
|
||||
if collect(Iterators.flatten(parsed_stecker)) != collect(unique(Iterators.flatten(parsed_stecker)))
|
||||
error("No letter may appear more than once in stecker settings.")
|
||||
end
|
||||
end
|
||||
|
30
src/hill.jl
30
src/hill.jl
@@ -1,4 +1,4 @@
|
||||
using Iterators
|
||||
using LinearAlgebra
|
||||
|
||||
"""
|
||||
Encrypts the given plaintext according to the Hill cipher.
|
||||
@@ -12,7 +12,7 @@ is thrown.
|
||||
|
||||
The matrix must be invertible modulo 26. If it is not, an error is thrown.
|
||||
"""
|
||||
function encrypt_hill{I <: Integer}(plaintext, key::Array{I, 2})
|
||||
function encrypt_hill(plaintext::AbstractString, key::AbstractArray{T, 2}) where {T<:Integer}
|
||||
if round(Integer, det(key)) % 26 == 0
|
||||
error("Key must be invertible mod 26.")
|
||||
end
|
||||
@@ -30,7 +30,7 @@ function encrypt_hill{I <: Integer}(plaintext, key::Array{I, 2})
|
||||
# split
|
||||
split_text = reshape(chars, (keysize, div(length(text), keysize)))
|
||||
|
||||
encrypted = mapslices(group -> 65 .+ ((key * group) .% 26), split_text, 1)
|
||||
encrypted = mapslices(group -> 65 .+ ((key * group) .% 26), split_text, dims = [1])
|
||||
|
||||
ans = IOBuffer()
|
||||
for group in encrypted
|
||||
@@ -42,24 +42,21 @@ function encrypt_hill{I <: Integer}(plaintext, key::Array{I, 2})
|
||||
end
|
||||
|
||||
|
||||
function encrypt_hill(plaintext, key::AbstractString)
|
||||
function encrypt_hill(plaintext::AbstractString, key::AbstractString)
|
||||
|
||||
if round(Integer, sqrt(length(key))) != sqrt(length(key))
|
||||
error("Hill key must be of square integer size.")
|
||||
end
|
||||
|
||||
matrix_dim = round(Integer, sqrt(length(key)))
|
||||
key_string = uppercase(letters_only(key))
|
||||
keys = map(x -> Int(x) - 65, collect(uppercase(letters_only(key))))
|
||||
|
||||
key_matrix = Array{Integer}(matrix_dim, matrix_dim)
|
||||
for i in 1:length(key)
|
||||
key_matrix[ind2sub([matrix_dim, matrix_dim], i)...] = Int(key_string[i]) - 65
|
||||
end
|
||||
key_matrix = reshape(keys, matrix_dim, matrix_dim)
|
||||
|
||||
encrypt_hill(plaintext, transpose(key_matrix))
|
||||
end
|
||||
|
||||
function minor{I <: Integer}(mat::Array{I, 2}, i, j)
|
||||
function minor(mat::AbstractArray{T, 2}, i, j) where {T<:Integer}
|
||||
d = det(mat[[1:i-1; i+1:end], [1:j-1; j+1:end]])
|
||||
round(Integer, d)
|
||||
end
|
||||
@@ -67,13 +64,13 @@ end
|
||||
"""
|
||||
Computes the adjugate matrix for given matrix.
|
||||
"""
|
||||
function adjugate{I <: Integer}(mat::Array{I, 2})
|
||||
arr = [(-1)^(i+j) * minor(mat, i, j) for (i, j) in product(1:size(mat, 1), 1:size(mat, 2))]
|
||||
function adjugate(mat::AbstractArray{T, 2}) where {T<:Integer}
|
||||
arr = [(-1)^(i+j) * minor(mat, i, j) for (i, j) in Iterators.product(1:size(mat, 1), 1:size(mat, 2))]
|
||||
ans = reshape(arr, size(mat))
|
||||
Array{Integer, 2}(transpose(ans))
|
||||
end
|
||||
|
||||
function decrypt_hill{I <: Integer}(ciphertext, key::Array{I, 2})
|
||||
function decrypt_hill(ciphertext, key::AbstractArray{T, 2}) where {T<:Integer}
|
||||
if ndims(key) != 2
|
||||
error("Key must be a two-dimensional matrix.")
|
||||
end
|
||||
@@ -97,12 +94,9 @@ function decrypt_hill(ciphertext, key::AbstractString)
|
||||
end
|
||||
|
||||
matrix_dim = round(Integer, sqrt(length(key)))
|
||||
key_string = uppercase(letters_only(key))
|
||||
keys = map(x -> Int(x) - 65, collect(uppercase(letters_only(key))))
|
||||
|
||||
key_matrix = Array{Integer}(matrix_dim, matrix_dim)
|
||||
for i in 1:length(key)
|
||||
key_matrix[ind2sub([matrix_dim, matrix_dim], i)...] = Int(key_string[i]) - 65
|
||||
end
|
||||
key_matrix = reshape(keys, matrix_dim, matrix_dim)
|
||||
|
||||
decrypt_hill(ciphertext, transpose(key_matrix))
|
||||
end
|
@@ -47,7 +47,7 @@ function decrypt_monoalphabetic(ciphertext, key::AbstractString)
|
||||
# working in lowercase; key is assumed only to have each element appearing once
|
||||
# and to be in lowercase
|
||||
# so decrypt_monoalphabetic("cb", "cbade…") is "ab"
|
||||
dict = Dict(a => Char(96 + search(lowercase(key), a)) for a in lowercase(key))
|
||||
dict = Dict(a => Char(96 + findfirst(i -> i == a, lowercase(key))) for a in lowercase(key))
|
||||
encrypt_monoalphabetic(lowercase(ciphertext), dict)
|
||||
end
|
||||
|
||||
|
@@ -11,8 +11,8 @@ function playfair_key_to_square(key::AbstractString, replacement)
|
||||
# delete duplicates etc from key
|
||||
key_sanitised = union(uppercase(letters_only(key)))
|
||||
# construct key square
|
||||
remaining = collect(filter(x -> (x != replacement[2] && findfirst(key_sanitised, x) == 0), 'A':'Z'))
|
||||
keysquare = reshape([key_sanitised; remaining], 5, 5)
|
||||
remaining = filter(x -> (x != replacement[2] && !(in(x, key_sanitised))), 'A':'Z')
|
||||
keysquare = reshape(collect(Iterators.flatten([key_sanitised; remaining])), 5, 5)
|
||||
return permutedims(keysquare, (2, 1)) # transpose() is deprecated
|
||||
end
|
||||
|
||||
@@ -39,7 +39,7 @@ combined=('I', 'J'), marks the characters which are to be combined in the text.
|
||||
"""
|
||||
function encrypt_playfair(plaintext, key::Array{Char, 2}; stripped=false, combined=('I', 'J'))
|
||||
if !stripped
|
||||
if findfirst(key, combined[2]) != 0
|
||||
if in(combined[2], key)
|
||||
error("Key must not contain symbol $(combined[2]), as it was specified to be combined.")
|
||||
end
|
||||
plaintext_sanitised = uppercase(letters_only(plaintext))
|
||||
@@ -88,8 +88,8 @@ function encrypt_playfair(plaintext, key::Array{Char, 2}; stripped=false, combin
|
||||
l1 = plaintext_sanitised[i]
|
||||
l2 = plaintext_sanitised[i+1]
|
||||
|
||||
l1pos = ind2sub((5, 5), findfirst(key, l1))
|
||||
l2pos = ind2sub((5, 5), findfirst(key, l2))
|
||||
l1pos = CartesianIndices((5, 5))[findfirst(i -> i == l1, key)]
|
||||
l2pos = CartesianIndices((5, 5))[findfirst(i -> i == l2, key)]
|
||||
|
||||
@assert l1pos != l2pos
|
||||
|
||||
@@ -124,7 +124,6 @@ Does not attempt to delete X's inserted as padding for double letters.
|
||||
"""
|
||||
function decrypt_playfair(ciphertext, key::Array{Char, 2}; combined=('I', 'J'))
|
||||
# to obtain the decrypting keysquare, reverse every row and every column
|
||||
keysquare = mapslices(reverse, key, 2)
|
||||
keysquare = permutedims(mapslices(reverse, permutedims(keysquare, (2, 1)), 2), (2, 1))
|
||||
keysquare = reverse(reverse(key, dims=1), dims=2)
|
||||
lowercase(encrypt_playfair(ciphertext, keysquare, combined=combined))
|
||||
end
|
||||
|
@@ -1,8 +1,8 @@
|
||||
function next_solitaire(deckIn)
|
||||
function next_solitaire(deckIn::AbstractVector{T}) :: AbstractVector{Integer} where {T<:Integer}
|
||||
# performs one round of Solitaire on the given deck
|
||||
# first joker
|
||||
deck = deckIn
|
||||
jokerPos = findin(deck, 53)[1]
|
||||
jokerPos = findfirst(i -> i == 53, deck)
|
||||
if jokerPos != length(deck)
|
||||
inter = deck[jokerPos+1]
|
||||
deck[jokerPos+1] = deck[jokerPos]
|
||||
@@ -14,7 +14,7 @@ function next_solitaire(deckIn)
|
||||
deck = rotateRight(deck)
|
||||
end
|
||||
# second joker
|
||||
jokerPos = findin(deck, 54)[1]
|
||||
jokerPos = findfirst(i -> i == 54, deck)
|
||||
if jokerPos <= length(deck) - 2
|
||||
inter = deck[jokerPos]
|
||||
deck[jokerPos] = deck[jokerPos+1]
|
||||
@@ -49,7 +49,7 @@ function next_solitaire(deckIn)
|
||||
split_deck[1] = split_deck[end]
|
||||
split_deck[end] = inter
|
||||
end
|
||||
deck = flatten(split_deck)
|
||||
deck = collect(Iterators.flatten(split_deck))
|
||||
# take bottom of deck and put it just above last card
|
||||
cardsToTake = (deck[end] > 52) ? 0 : deck[end]
|
||||
|
||||
@@ -57,28 +57,34 @@ function next_solitaire(deckIn)
|
||||
append!(intermediate, [deck[end]])
|
||||
deck = intermediate
|
||||
|
||||
return deck
|
||||
return collect(deck)
|
||||
end
|
||||
|
||||
function keychar_from_deck(deck::Vector)
|
||||
function keychar_from_deck(deck::AbstractVector{T}) :: Integer where {T<:Integer}
|
||||
# given a deck, returns an integer which is the Solitaire key value
|
||||
# output by that deck
|
||||
deck[((deck[1]==54 ? 53 : deck[1]) % length(deck)) + 1]
|
||||
end
|
||||
|
||||
type SolitaireKeyStream
|
||||
deck::Vector
|
||||
struct SolitaireKeyStreamStruct
|
||||
deck::AbstractVector{Integer}
|
||||
end
|
||||
|
||||
Base.start(b::SolitaireKeyStream) = (next_solitaire(b.deck))
|
||||
function Base.next(b::SolitaireKeyStream, state)
|
||||
curState = state
|
||||
function Base.iterate(b::SolitaireKeyStreamStruct)
|
||||
(0, next_solitaire(b.deck))
|
||||
end
|
||||
|
||||
function Base.iterate(b::SolitaireKeyStreamStruct, state)
|
||||
curState = state::AbstractVector{Integer}
|
||||
while keychar_from_deck(curState) > 52
|
||||
curState = next_solitaire(curState)
|
||||
end
|
||||
(keychar_from_deck(curState), next_solitaire(curState))
|
||||
(keychar_from_deck(curState)::Integer, next_solitaire(curState))
|
||||
end
|
||||
|
||||
function SolitaireKeyStream(initialDeck::AbstractVector{T}) where {T<:Integer}
|
||||
Iterators.filter(i -> i <= 52, Iterators.drop(SolitaireKeyStreamStruct(initialDeck), 1))
|
||||
end
|
||||
Base.done(b::SolitaireKeyStream, state) = false
|
||||
|
||||
"""
|
||||
Encrypts the given plaintext according to the Solitaire cipher.
|
||||
@@ -86,16 +92,11 @@ The key may be given either as a vector initial deck, where the cards are
|
||||
1 through 54 (the two jokers being 53, 54), or as a string.
|
||||
Schneier's keying algorithm is used to key the deck if the key is a string.
|
||||
"""
|
||||
function encrypt_solitaire(string, initialDeck::Vector)
|
||||
function encrypt_solitaire(string, initialDeck::AbstractVector{T}) :: AbstractString where {T<:Integer}
|
||||
inp = uppercase(letters_only(string))
|
||||
ans = ""
|
||||
i = 0
|
||||
for keyval in SolitaireKeyStream(initialDeck)
|
||||
i += 1
|
||||
if i > length(inp)
|
||||
break
|
||||
end
|
||||
ans *= encrypt_caesar(inp[i], keyval)
|
||||
for (keyval::Integer, input::Char) in zip(SolitaireKeyStream(initialDeck), collect(inp))
|
||||
ans *= encrypt_caesar(input, keyval)
|
||||
end
|
||||
return ans
|
||||
end
|
||||
@@ -110,17 +111,13 @@ function decrypt_solitaire(string, initialDeck::Vector)
|
||||
inp = uppercase(letters_only(string))
|
||||
ans = ""
|
||||
i = 0
|
||||
for keyval in SolitaireKeyStream(initialDeck)
|
||||
i += 1
|
||||
if i > length(inp)
|
||||
break
|
||||
end
|
||||
ans *= decrypt_caesar(inp[i], keyval)
|
||||
for (keyval, input) in zip(SolitaireKeyStream(initialDeck), collect(inp))
|
||||
ans *= decrypt_caesar(input, keyval)
|
||||
end
|
||||
return ans
|
||||
end
|
||||
|
||||
function key_deck(key::AbstractString)
|
||||
function key_deck(key::AbstractString) :: AbstractVector{Integer}
|
||||
# returns the Solitaire deck after it has been keyed with the given string
|
||||
deck = collect(1:54)
|
||||
for keyval in uppercase(letters_only(key))
|
||||
@@ -133,8 +130,9 @@ function key_deck(key::AbstractString)
|
||||
deck
|
||||
end
|
||||
|
||||
function encrypt_solitaire(string, key::AbstractString)
|
||||
encrypt_solitaire(string, key_deck(key))
|
||||
function encrypt_solitaire(string::AbstractString, key::AbstractString) :: AbstractString
|
||||
key = key_deck(key)
|
||||
encrypt_solitaire(string, key)
|
||||
end
|
||||
|
||||
function decrypt_solitaire(string, key::AbstractString)
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using Statistics
|
||||
|
||||
"""
|
||||
Encrypts the given string using the Vigenere cipher according to the given vector of offsets.
|
||||
For example, encrypt_vigenere("ab", [0, 1]) returns "AC".
|
||||
@@ -14,7 +16,7 @@ For example, decrypt_vigenere("ac", [0, 1]) returns "ab".
|
||||
"""
|
||||
function decrypt_vigenere(ciphertext, key::Array)
|
||||
# ciphertext: string; key: vector of integer offsets, so [0, 1] decrypts "ac" as "ab"
|
||||
lowercase(encrypt_vigenere(ciphertext, 26-key))
|
||||
lowercase(encrypt_vigenere(ciphertext, map(x -> 26-x, key)))
|
||||
end
|
||||
|
||||
"""
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
# docs examples
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
@test encrypt_caesar("THIS CODE WAS INVENTED BY JULIUS CAESAR", 3) == "WKLV FRGH ZDV LQYHQWHG EB MXOLXV FDHVDU"
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
@test (encrypt_enigma("AAA", [1,2,3], "AAA") == "BDZ")
|
||||
@test (decrypt_enigma("BDZ", [1,2,3], "AAA") == "aaa")
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
# Wikipedia examples
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
@test encrypt_monoalphabetic("aBcbD", Dict{Char, Char}('a' => '5', 'B' => '@', 'b' => 'o', 'D' => 'D')) == "5@coD"
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
# Wikipedia example
|
||||
@test encrypt_playfair("Hide the gold in the tree stump", "playfair example") == "BMODZBXDNABEKUDMUIXMMOUVIF"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
@test encrypt_portas("DEFENDTHEEASTWALLOFTHECASTLE", "FORTIFICATION") == uppercase("synnjscvrnrlahutukucvryrlany")
|
||||
@test decrypt_portas("synnjscvrnrlahutukucvryrlany", "FORTIFICATION") == lowercase("DEFENDTHEEASTWALLOFTHECASTLE")
|
||||
|
@@ -1,8 +1,17 @@
|
||||
using ClassicalCiphers
|
||||
using Test
|
||||
|
||||
tests = ["vigenere", "monoalphabetic", "solitaire",
|
||||
"caesar", "portas", "affine", "hill", "playfair",
|
||||
"enigma"]
|
||||
tests = [
|
||||
"playfair",
|
||||
"vigenere",
|
||||
"monoalphabetic",
|
||||
"caesar",
|
||||
"portas",
|
||||
"affine",
|
||||
"enigma",
|
||||
"hill",
|
||||
"solitaire",
|
||||
]
|
||||
|
||||
println("Running tests:")
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
@test encrypt_solitaire("aaaaaaaaaaaaaaa", "") == "EXKYIZSGEHUNTIQ"
|
||||
@test encrypt_solitaire("aaaaaaaaaaaaaaa", "f") == "XYIUQBMHKKJBEGY"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
using ClassicalCiphers
|
||||
using Base.Test
|
||||
using Test
|
||||
|
||||
# doc examples
|
||||
@test encrypt_vigenere("ab", [0, 1]) == "AC"
|
||||
@@ -9,7 +9,7 @@ using Base.Test
|
||||
|
||||
# others
|
||||
|
||||
@test decrypt_vigenere("DYIMXMESTEZDPNFVVAMJ", [11, 18, 5, 13, 12, 9, 14]-1) == "theamericanshaverobb"
|
||||
@test decrypt_vigenere("DYIMXMESTEZDPNFVVAMJ", map(x -> x - 1, [11, 18, 5, 13, 12, 9, 14])) == "theamericanshaverobb"
|
||||
|
||||
@test decrypt_vigenere("DYIMXMESTEZDPNFVVAMJ", "kremlin") == "theamericanshaverobb"
|
||||
|
||||
|
Reference in New Issue
Block a user