Enigma (jl)


import Base.getindex,Base.inv,Base.*,Base.^
    
struct Perm
    permutation::Array{Integer}
end

const ι=Perm([(i)%26+1 for i in 0:25])
const ρ=Perm([(i+1)%26+1 for i in 0:25])

function (π::Perm)(i::Integer)
    π.permutation[i]
end

function (π::Perm)(c::Char)
    Char(π(Int(c)-Int('a')+1)+Int('a')-1)    
end


function inv(π::Perm)
    res=zeros(Integer,length(π.permutation))
    for i in 1:length(π.permutation)
        res[π(i)]=i
    end
    Perm(res)
end

function *(π::Perm,ψ::Perm)
    Perm([π(ψ(i)) for i in 1:length(π.permutation)])
end

function ^(π::Perm,i::Integer)
    i==0 && return ι
    i==1 && return π
    i>1  && return π*(π^(i-1))
    i<0  && return (π^(-1))^i
end


function initSwap(s::String)
    res=collect(1:26)
    for i in 0:(length(s)÷2-1)
        res[Int(s[2*i+1])-Int('a')+1]=Int(s[2*i+2]-Int('a')+1)
        res[Int(s[2*i+2])-Int('a')+1]=Int(s[2*i+1]-Int('a')+1)
    end
    Perm(res)
end

abstract type Swaps end

struct Plugboard <: Swaps
    wiring:: Perm
    Plugboard(s::String) = new(initSwap(s)) 
end

struct Reflector <: Swaps
    wiring:: Perm
    Reflector(s::String) = new(initSwap(s)) 
end

mutable struct Rotor
    wiring:: Perm
    pin:: Integer
    position:: Integer
end

mutable struct Enigma
    rotors:: Array{Rotor}
    reflector:: Reflector
    plugboard:: Plugboard
end

function Rotor(s::String,pin::Integer=1)
    r=[ Int(i)-Int('a')+1 for i in s ]
    Rotor(Perm(r),pin,1)
end

function getperm(r::Swaps)
    r.wiring
end

function getperm(r::Rotor)
    σ=ρ^(r.position-1)
    σ*(r.wiring)*σ^-1
end

function rotate!(r::Rotor)
    r.position %=26
    r.position +=1
    r.position==r.pin
end

function set!(r::Rotor,c::Char)
    r.position=(Int(c)-Int('a'))%26+1
end

function getperm(E::Enigma)
    π=getperm(E.plugboard)
    μ=reduce(*,[ getperm(x) for x in reverse(E.rotors) ])
    σ=getperm(E.reflector)
    π*μ^(-1)*σ*μ*π
end

function step!(E::Enigma)
    step=true
    for rt in E.rotors
        step && (step=rotate!(rt))
    end
end

function (E::Enigma)(s::String)
    map(s) do c
        e=getperm(E)(c)
        step!(E)
        e
    end
end

function setkey!(E::Enigma,s::String)
    for x in zip(E.rotors,s)
        set!(x[1],x[2])
    end
end

RA="qwaszxcderfvbgtyhnmjuiklop"
RB="vpwoeirutyalskdjfhgzmxncbq"
RC="plmkoijnbhuygvcftrdxzsewaq"
Rf="zxcvasdfqwertyghbnmjuiklop"
Pb="alpestvj"

ARotorA=Rotor(RA)
ARotorB=Rotor(RB)
ARotorC=Rotor(RC)
ARef=Reflector(Rf)
APlg=Plugboard(Pb)
AliceEnigma=Enigma([ARotorA,ARotorB,ARotorC],ARef,APlg)

BRotorA=Rotor(RA)
BRotorB=Rotor(RB)
BRotorC=Rotor(RC)
BRef=Reflector(Rf)
BPlg=Plugboard(Pb)
BobEnigma=Enigma([BRotorA,BRotorB,BRotorC],BRef,BPlg)

setkey!(AliceEnigma,"cil")
setkey!(BobEnigma,"cil")

AliceMsg=AliceEnigma("thisisatestmessage")
BobMsg=BobEnigma(AliceMsg)