Add source files this time

This commit is contained in:
Smaug123
2016-01-03 21:43:29 +00:00
parent d0c4f0379e
commit 949816f7e0
8 changed files with 312 additions and 0 deletions

11
src/caesar.jl Normal file
View File

@@ -0,0 +1,11 @@
function encrypt_caesar(plaintext, key::Integer)
# plaintext: string; key: integer offset, so k=1 sends "a" to "b"
key = ((key-1) % 26) + 1
encrypt_monoalphabetic(plaintext, join([collect(Char(97+key):'z'); collect('a':Char(97+key-1))]))
end
function decrypt_caesar(ciphertext, key::Integer)
# ciphertext: string; key: integer offset, so k=1 decrypts "B" as "A"
key = ((key-1) % 26) + 1
encrypt_caesar(ciphertext, 26-key)
end

42
src/common.jl Normal file
View File

@@ -0,0 +1,42 @@
function letters_only(text)
# text: string; removes all non-alphabetic characters
filter(x -> ('A' <= x <= 'Z' || 'a' <= x <= 'z'), text)
end
function rotateRight(arr, n)
# implementation of the Mathematica function RotateRight
ans = copy(arr)
for i in 1:length(arr)
ans[i] = arr[((2*length(ans)+i-n-1) % length(ans)) + 1]
end
ans
end
function rotateLeft(arr, n)
# implementation of the Mathematica function RotateLeft
ans = copy(arr)
for i in 1:length(arr)
ans[i] = arr[((i+n-1) % length(ans)) + 1]
end
ans
end
flatten{T}(a::Array{T,1}) = any(map(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
# on its elements
arrinternal = map(func, arr)
currans = Vector{Integer}[[arr[1]]]
for i in 2:length(arr)
if arrinternal[i] != arrinternal[i-1]
append!(currans, Vector{Integer}[[arr[i]]])
else
append!(currans[end], [arr[i]])
end
end
currans
end

28
src/monoalphabetic.jl Normal file
View File

@@ -0,0 +1,28 @@
function encrypt_monoalphabetic(plaintext, key::Dict)
# plaintext: string; key: dictionary of {'a' => 'b'}, etc, for replacing 'a' with 'b'
join([(i in keys(key) ? key[i] : i) for i in plaintext], "")
end
function decrypt_monoalphabetic(ciphertext, key::Dict)
# ciphertext: string; key: dictionary of {'a' => 'b'}, etc, where the plaintext 'a' was
# replaced by ciphertext 'b'. No character should appear more than once
# as a value in {key}.
encrypt_monoalphabetic(ciphertext, Dict{Char, Char}([reverse(a) for a in key]))
end
function encrypt_monoalphabetic(plaintext, key::AbstractString)
# plaintext: string; key: string of length 26, first character is the image of 'a', etc
# working in lowercase; key is assumed only to have each element appearing once
# and to be in lowercase.
dict = Dict{Char, Char}(map(x -> (x[1]+96, x[2]), enumerate(key)))
encrypt_monoalphabetic(lowercase(plaintext), dict)
end
function decrypt_monoalphabetic(ciphertext, key::AbstractString)
# ciphertext: string; key: string of length 26, first character is the image of 'a', etc
# 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 = [(a => Char(96 + search(lowercase(key), a))) for a in lowercase(key)]
encrypt_monoalphabetic(lowercase(ciphertext), dict)
end

132
src/solitaire.jl Normal file
View File

@@ -0,0 +1,132 @@
include("common.jl")
function next_solitaire(deckIn)
# performs one round of Solitaire on the given deck
# first joker
deck = deckIn
jokerPos = findin(deck, 53)[1]
if jokerPos != length(deck)
inter = deck[jokerPos+1]
deck[jokerPos+1] = deck[jokerPos]
deck[jokerPos] = inter
else
inter = deck[end]
deck[end] = deck[1]
deck[1] = inter
deck = rotateRight(deck)
end
# second joker
jokerPos = findin(deck, 54)[1]
if jokerPos <= length(deck) - 2
inter = deck[jokerPos]
deck[jokerPos] = deck[jokerPos+1]
deck[jokerPos + 1] = deck[jokerPos + 2]
deck[jokerPos + 2] = inter
elseif jokerPos == length(deck) - 1
inter = deck[length(deck)-1]
inter1 = deck[length(deck)]
deck[end] = deck[1]
deck[length(deck)-1] = inter1
deck[1] = inter
deck = rotateRight(deck, 1)
elseif jokerPos == length(deck)
inter = deck[1]
inter1 = deck[end]
deck[1] = deck[2]
deck[2] = inter1
deck[end] = inter
deck = rotateRight(deck,1)
end
# triple-cut
split = splitBy(deck, x -> x > 52)
if deck[1] > 52 && deck[end] > 52
1
# do nothing
elseif deck[1] > 52
split = rotateRight(split, 1)
elseif deck[end] > 52
split = rotateLeft(split, 1)
else
inter = split[1]
split[1] = split[end]
split[end] = inter
end
deck = flatten(split)
# take bottom of deck and put it just above last card
cardsToTake = (deck[end] > 52) ? 0 : deck[end]
intermediate = rotateLeft(deck[1:length(deck)-1], cardsToTake)
append!(intermediate, [deck[end]])
deck = intermediate
return deck
end
function keychar_from_deck(deck::Vector)
# 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
end
Base.start(b::SolitaireKeyStream) = (next_solitaire(b.deck))
function Base.next(b::SolitaireKeyStream, state)
curState = state
while keychar_from_deck(curState) > 52
curState = next_solitaire(curState)
end
(keychar_from_deck(curState), next_solitaire(curState))
end
Base.done(b::SolitaireKeyStream, state) = false
function encrypt_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 *= encrypt_caesar(inp[i], keyval)
end
return ans
end
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)
end
return ans
end
function key_deck(key::AbstractString)
# returns the Solitaire deck after it has been keyed with the given string
deck = collect(1:54)
for keyval in uppercase(letters_only(key))
deck = next_solitaire(deck)
cardsToTake = Int(keyval)-64
intermediate = rotateLeft(deck[1:length(deck)-1], cardsToTake)
append!(intermediate, [deck[end]])
deck = intermediate
end
deck
end
function encrypt_solitaire(string, key::AbstractString)
encrypt_solitaire(string, key_deck(key))
end
function decrypt_solitaire(string, key::AbstractString)
decrypt_solitaire(string, key_deck(key))
end

39
src/vigenere.jl Normal file
View File

@@ -0,0 +1,39 @@
"""
Encrypts the given string using the Vigenere cipher according to the given vector of offsets.
For example, encrypt_vigenere("ab", [0, 1]) returns "ac".
"""
function encrypt_vigenere(plaintext, key::Array)
# plaintext: string; key: vector of integer offsets, so [0, 1] encrypts "ab" as "ac"
ans = [encrypt_caesar(char, key[(i-1) % length(key)+1]) for (i, char) in enumerate(letters_only(plaintext))]
join(ans, "")
end
"""
Decrypts the given string using the Vigenere cipher according to the given vector of offsets.
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"
encrypt_vigenere(ciphertext, 26-key)
end
"""
Encrypts the given string using the Vigenere cipher according to the given keystring.
For example, encrypt_vigenere("ab", "ab") returns "ac".
"""
function encrypt_vigenere(ciphertext, key::AbstractString)
# ciphertext: string; key: string, so "ab" encrypts "ab" as "ac"
encrypt_vigenere(ciphertext, [Int(i)-97 for i in lowercase(letters_only(key))])
end
"""
Decrypts the given string using the Vigenere cipher according to the given keystring.
For example, decrypt_vigenere("ab", "ac") returns "ab".
"""
function decrypt_vigenere(plaintext, key::AbstractString)
# plaintext: string; key: string, so "ab" decrypts "ac" as "ab"
decrypt_vigenere(plaintext, [Int(i)-97 for i in lowercase(letters_only(key))])
end

15
test/monoalphabetic.jl Normal file
View File

@@ -0,0 +1,15 @@
using ClassicalCiphers
using Base.Test
@test encrypt_monoalphabetic("aBcbD", Dict{Char, Char}('a' => '5', 'B' => '@', 'b' => 'o', 'D' => 'D')) == "5@coD"
# when given a string second argument, it lowercases everything
@test encrypt_monoalphabetic("THIS CODE WAS INVENTED BY JULIUS CAESAR", "DEFGHIJKLMNOPQRSTUVWXYZABC") == "WKLV FRGH ZDV LQYHQWHG EB MXOLXV FDHVDU"
@test decrypt_monoalphabetic("5@coD", Dict{Char, Char}('a' => '5', 'B' => '@', 'b' => 'o', 'D' => 'D')) == "aBcbD"
@test decrypt_monoalphabetic("WKLV FRGH ZDV LQYHQWHG EB MXOLXV FDHVDU", "DEFGHIJKLMNOPQRSTUVWXYZABC") == lowercase("THIS CODE WAS INVENTED BY JULIUS CAESAR")
@test encrypt_caesar("THIS CODE WAS INVENTED BY JULIUS CAESAR", 3) == lowercase("WKLV FRGH ZDV LQYHQWHG EB MXOLXV FDHVDU")
@test decrypt_caesar("WKLV FRGH ZDV LQYHQWHG EB MXOLXV FDHVDU", 3) == lowercase("THIS CODE WAS INVENTED BY JULIUS CAESAR")

28
test/solitaire.jl Normal file
View File

@@ -0,0 +1,28 @@
using ClassicalCiphers
using Base.Test
@test encrypt_solitaire("aaaaaaaaaaaaaaa", "") == lowercase("EXKYIZSGEHUNTIQ")
@test encrypt_solitaire("aaaaaaaaaaaaaaa", "f") == lowercase("XYIUQBMHKKJBEGY")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "fo") == lowercase("TUJYMBERLGXNDIW")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "foo") == lowercase("ITHZUJIWGRFARMW")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "a") == lowercase("XODALGSCULIQNSC")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "aa") == lowercase("OHGWMXXCAIMCIQP")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "aaa") == lowercase("DCSQYHBQZNGDRUT")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "b") == lowercase("XQEEMOITLZVDSQS")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "bc") == lowercase("QNGRKQIHCLGWSCE")
@test encrypt_solitaire("AAAAAAAAAAAAAAA", "bcd") == lowercase("FMUBYBMAXHNQXCJ")
@test encrypt_solitaire("AAAAAAAAAAAAAAAAAAAAAAAAA", "cryptonomicon") == lowercase("SUGSRSXSWQRMXOHIPBFPXARYQ")
@test encrypt_solitaire("SOLITAIREX", "cryptonomicon") == lowercase("KIRAKSFJAN")
@test decrypt_solitaire("EXKYI ZSGEH UNTIQ", "") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("XYIUQ BMHKK JBEGY ", "f") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("TUJYM BERLG XNDIW", "fo") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("ITHZU JIWGR FARMW ", "foo") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("XODAL GSCUL IQNSC ", "a") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("OHGWM XXCAI MCIQP ", "aa") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("DCSQY HBQZN GDRUT ", "aaa") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("XQEEM OITLZ VDSQS ", "b") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("QNGRK QIHCL GWSCE ", "bc") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("FMUBY BMAXH NQXCJ", "bcd") == "aaaaaaaaaaaaaaa"
@test decrypt_solitaire("SUGSR SXSWQ RMXOH IPBFP XARYQ", "cryptonomicon") == "aaaaaaaaaaaaaaaaaaaaaaaaa"
@test decrypt_solitaire("KIRAK SFJAN", "cryptonomicon") == "solitairex"

17
test/vigenere.jl Normal file
View File

@@ -0,0 +1,17 @@
using ClassicalCiphers
using Base.Test
# doc examples
@test encrypt_vigenere("ab", [0, 1]) == "ac"
@test decrypt_vigenere("ac", [0, 1]) == "ab"
@test encrypt_vigenere("ab", "ab") == "ac"
@test decrypt_vigenere("ac", "ab") == "ab"
# others
@test decrypt_vigenere("DYIMXMESTEZDPNFVVAMJ", [11, 18, 5, 13, 12, 9, 14]-1) == lowercase("THEAMERICANSHAVEROBB")
@test decrypt_vigenere("DYIMXMESTEZDPNFVVAMJ", "kremlin") == lowercase("THEAMERICANSHAVEROBB")
@test encrypt_vigenere("THEAMERICANSHAVEROBB", "kremlin") ==
lowercase("DYIMXMESTEZDPNFVVAMJ")