# Functional Ciphers in Ruby

Ciphers are an algorithm for encrypting or decrypting text. They have been used since ancient times. Julius Caesar famously encrypted military messages via a cipher that shifted all letters by a constant value. Today, this algorithm is known as the ROT family of ciphers.

We want to write some code that will show us multiple passes of ROT encryption on some input text, using some of Ruby’s functional constructs.

## ROT5

The ROT5 algorithm rotates the alphabet by 5 characters. We could implement it as follows:

``````rot5 = ->(text) do
alphabet = ("a".."z").to_a
key = Hash[alphabet.zip(alphabet.rotate(5))]
text.each_char.inject("") { |encrypted, char| encrypted + key[char] }
end
``````

The key is a hash that maps inputs from the standard alphabet to the rotated one. It looks like: `{ "a" => "f", "b" => "g", ... }`. We use this key to convert each character of the input string to its rotated value.

This works as expected:

``````rot5.call("password")
# => "ufxxbtwi"
rot5.call("supersecret")
# => "xzujwxjhwjy"
``````

We can easily extend this to allow us to shift by any value by adding another argument:

``````rot = ->(rotation, text) do
alphabet = ("a".."z").to_a
key = Hash[alphabet.zip(alphabet.rotate(rotation))]
text.each_char.inject("") { |encrypted, char| encrypted + key[char] }
end

# => "ufxxbtwi"
# => "zkccgybn"
``````

## Multiple applications

We want to see what happens when you apply a ROT function multiple times to a value. We could manually write `rot5(rot5(rot5("password")))`, however that is not very flexible and doesn’t even show the intermediate steps. Instead, we are going to take inspiration from `iterate` in Haskell.

Haskell’s `iterate` function takes a function and starting value and returns an infinite lazy list of recursive applications of the function to the value. In other words:

``````iterate f x == [x, f(x), f(f(x)), f(f(f(x))), ...]
``````

To implement this in Ruby, we are going to need `Enumerator`.

## Ruby’s `Enumerator`

One of the lesser-known core classes in Ruby, `Enumerator` implements the internal and external iteration patterns. `Enumerator#new` take a block with a yielder parameter and adds all values sent to the yielder to its list.

``````numbers = Enumerator.new do |yielder|
yielder << 1
yielder << 2
yielder << 3
end

numbers.first(3)
# => [1, 2, 3]
``````

`Enumerator` is lazy-ish. Take the following infinite iterator:

``````infinite = Enumerator.new do |yielder|
x = 1
loop do
yielder << x
x +=1
end
end
``````

We can ask for the first 10 values without having to calculate the entire series.

``````infinite.first(10)
# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
``````

However, using a method such as `map` that acts on every item will never return because this is an infinite series. We will need true laziness to get this one to work.

``````infinite.lazy.map { |n| n * 2 }
# => #<Enumerator::Lazy: ...>

infinite.lazy.map { |n| n * 2 }.first(10)
# => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
``````

Calling `map` on a lazy enumerator won’t actually execute until you ask for some items in the series, and even then it will only execute for those items. We’ve written previously about how to take advantage of this laziness to refactor code.

## Building `iterate`

The Haskell implementation is deceptively simple:

``````iterate :: (a -> a) -> a -> [a]
iterate f x =  x : iterate f (f x)
``````

It just keeps recurring and appending to the list (lazily of course).

The Ruby implementation is a bit more verbose, and uses iteration rather than recursion.

``````iterate = -> (x, &block) do
Enumerator.new do |yielder|
loop do
yielder << x
x = block.call(x)
end
end.lazy
end
``````

This method accepts a starting value and a block. On each iteration of the loop, it calls the block with the value of the previous iteration. The result is an infinite, lazy enumerator.

``````iterate.call("x") { |x| "f(#{x})" }.first(5)
# => ["x", "f(x)", "f(f(x))", "f(f(f(x)))", "f(f(f(f(x))))"]

iterate.call(1) { |x| x * 2 }.first(10)
# => [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
``````

## Multiple applications of ROT5

Now that we have `iterate`, we can finally try multiple applications of ROT5. Instead of passing a block (which is just an anonymous function), we can directly pass the named function `rot5`:

``````iterate.call("password", &rot5).first(5)
# => ["password", "ufxxbtwi", "zkccgybn", "ephhldgs", "jummqilx"]

iterate.call("supersecret", &rot5).first(5)
# => ["supersecret", "xzujwxjhwjy", "cezobcombod", "hjetghtrgti", "mojylmywlyn"]
``````

This is exactly what we want. However, we run into a problem if we try to use our more generic function `rot`.

``````iterate.call("password", &rot).first(5)
# => ArgumentError: wrong number of arguments (1 for 2)
``````

`rot` expects two arguments, but `iterate` only passes it one. To get around this, we need to use currying.

## Currying

Currying allows us to call a function with only part of its arguments and it will return another function that requires the remainder.

``````two_text = ->(text1, text2) { "#{text1} #{text2}" }.curry
# => #<Proc: (lambda)>
hello = two_text.call("hello")
# => #<Proc: (lambda)>

hello.call("world")
# => "hello world"

two_text.call("currying").call("works!")
# => "currying works!"
``````

If we curry `rot`, we can partially apply it and then pass it into `iterate`:

``````rot = ->(rotation, text) do
alphabet = ("a".."z").to_a
key = Hash[alphabet.zip(alphabet.rotate(rotation))]
text.each_char.inject("") { |encrypted, char| encrypted + key[char] }
end.curry

# => ["password", "whzzdvyk", "doggkcfr", "kvnnrjmy", "rcuuyqtf"]
``````

Great! Now we can encrypt any text with any number of passes through any ROT algorithm and see all the intermediate values.

## Deconstructing ROT

Calling a ROT algorithm multiple times on itself does not make it any harder to decrypt. ROTX of ROTY is the same as ROT X + Y

``````rot.call(10, rot.call(5, "password"))
# => "ephhldgs"

# => "ephhldgs"
``````

Also, every multiple of 26 is just plain text:

``````rot.call(26, "password")

``````

This can easily be seen when using `iterate`:

``````iterate.call("password", &rot.call(13)).first(5)
# =>
[
"cnffjbeq", # ROT13
"cnffjbeq", # ROT39
]
``````

Building on the two facts above, we can use `iterate` to brute-force any ROT-encrypted text:

``````rot.call(17, "thisisasupersecretmessage")
# => "kyzjzjrjlgvijvtivkdx"

iterate("kyzjzjrjlgvijvtivkdx", &rot.call(1)).first(26)
# The decrypted message will be one of the 26 messages below:
# =>
[
"kyzjzjrjlgvijvtivkdvjjrxv",
"lzakakskmhwjkwujwlewkksyw",
"mablbltlnixklxvkxmfxlltzx",
"nbcmcmumojylmywlyngymmuay",
"ocdndnvnpkzmnzxmzohznnvbz",
"pdeoeowoqlanoaynapiaoowca",
"qefpfpxprmbopbzobqjbppxdb",
"rfgqgqyqsncpqcapcrkcqqyec",
"sghrhrzrtodqrdbqdsldrrzfd",
"thisisasupersecretmessage", # Gotcha!
"uijtjtbtvqfstfdsfunfttbhf",
"vjkukucuwrgtugetgvoguucig",
"wklvlvdvxshuvhfuhwphvvdjh",
"xlmwmwewytivwigvixqiwweki",
"ymnxnxfxzujwxjhwjyrjxxflj",
"znoyoygyavkxykixkzskyygmk",
"aopzpzhzbwlyzljylatlzzhnl",
"bpqaqaiacxmzamkzmbumaaiom",
"cqrbrbjbdynabnlancvnbbjpn",
"drscsckcezobcombodwocckqo",
"estdtdldfapcdpncpexpddlrp",
"ftueuemegbqdeqodqfyqeemsq",
"guvfvfnfhcrefrpergzrffntr",
"hvwgwgogidsfgsqfshasggous",
"iwxhxhphjetghtrgtibthhpvt",
"jxyiyiqikfuhiushujcuiiqwu"
]
``````