lib/crypto: Added cryptography basic algos to lib
authorLucas Bajolet <r4pass@hotmail.com>
Tue, 23 Sep 2014 13:52:25 +0000 (09:52 -0400)
committerLucas Bajolet <r4pass@hotmail.com>
Tue, 23 Sep 2014 13:52:25 +0000 (09:52 -0400)
Signed-off-by: Lucas Bajolet <r4pass@hotmail.com>

lib/crypto.nit [new file with mode: 0644]

diff --git a/lib/crypto.nit b/lib/crypto.nit
new file mode 100644 (file)
index 0000000..a84358f
--- /dev/null
@@ -0,0 +1,218 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Mix of all things cryptography-related
+module crypto
+
+redef class Char
+       # Rotates self of `x`
+       #
+       # NOTE: works on letters only
+       #
+       #    assert 'x'.rot(6) == 'd'
+       #    assert 'T'.rot(15) == 'I'
+       #    assert '1'.rot(10) == '1'
+       #    assert '$'.rot(10) == '$'
+       #    assert 'z'.rot(-2) == 'x'
+       fun rot(x: Int): Char do
+               if not is_letter then return self
+               x = x % 26
+               if x < 0 then x += 26
+               var up = false
+               var val = ascii
+               if is_upper then
+                       up = true
+                       val += 32
+               end
+               val += x
+               if val > 122 then val -= 26
+               if up then val -= 32
+               return val.ascii
+       end
+end
+
+redef class String
+       # Performs a Rotation of `x` on each letter of self
+       #
+       # Works by replacing every character in `self` by its
+       # rotated char.
+       #
+       # Say we have a rotation of `3` (Caesar rotation, for
+       # culture) for a string : "aybabtu"
+       #
+       # a, rotated by 3 becomes d
+       # y, rotated by 3 becomes b
+       # b, rotated by 3 becomes e
+       # t, rotated by 3 becomes w
+       # u, rotated by 3 becomes x
+       #
+       # We then replace every letter in our original string by
+       # their rotated representations, therefore yielding : "dbedewx"
+       #
+       #    assert "All your base are belong to us".rot(13) == "Nyy lbhe onfr ner orybat gb hf"
+       #    assert "This is no moon.".rot(4).rot(22) == "This is no moon."
+       #
+       # NOTE : Works on letters only
+       # NOTE : This cipher is symmetrically decrypted with an `x` of 26-`x`
+       fun rot(x: Int): String do
+               var rot = x % 26
+               if rot < 0 then rot += 26
+               var d = new FlatBuffer.with_capacity(length)
+               var p = 0
+               for i in chars do
+                       d.add i.rot(rot)
+               end
+               return d.to_s
+       end
+
+       # Returns a rail-fence cipher from `self` with `depth` rails
+       #
+       # Rail works by drawing a zig-zag pattern on `depth` rails.
+       #
+       # Say we have "fuckingbehemoth".railfence(4)
+       #
+       # This happens in-memory :
+       #       f.....g.....o..
+       #       .u...n.b...m.t.
+       #       ..c.i...e.e...h
+       #       ...k.....h.....
+       #
+       # Therefore, yielding the ciphertext : "fgounbmtcieehkh"
+       #
+       #    assert "fuckingbehemoth".railfence(4) == "fgounbmtcieehkh"
+       fun railfence(depth: Int): String do
+               var lines = new Array[FlatBuffer].with_capacity(depth)
+               var up = false
+               for i in [0..depth[ do
+                       lines[i] = new FlatBuffer.with_capacity(length)
+               end
+               var curr_depth = 0
+               for i in chars do
+                       for j in [0..depth[ do
+                               if j == curr_depth then
+                                       lines[j].add i
+                               else
+                                       lines[j].add '.'
+                               end
+                       end
+                       if up then
+                               curr_depth -= 1
+                       else
+                               curr_depth += 1
+                       end
+                       if curr_depth == 0 then
+                               up = false
+                       end
+                       if curr_depth == (depth - 1) then
+                               up = true
+                       end
+               end
+               var r = new FlatBuffer.with_capacity(length)
+               for i in lines do
+                       r.append i.to_s.replace(".", "")
+               end
+               return r.to_s
+       end
+
+       # Transforms a rail-fence-encrypted String to its original
+       #
+       #    assert "fgounbmtcieehkh".unrail(4) == "fuckingbehemoth"
+       fun unrail(depth: Int): String do
+               var dots = "." * length
+               var arr = new FlatBuffer.from(dots)
+               var start = 0
+               var paces = depth.unrail_paces
+               for i in [0..depth[ do
+                       var lp = paces[i].first
+                       var rp = paces[i].second
+                       var pos = i
+                       var l = true
+                       while pos < length do
+                               arr[pos] = chars[start]
+                               if l then
+                                       pos += lp
+                                       l = false
+                               else
+                                       pos += rp
+                                       l = true
+                               end
+                               start += 1
+                       end
+               end
+               return arr.to_s
+       end
+end
+
+redef class Int
+       # Generates the paces for each depth.
+       #
+       # Each entry of the returned array is a couple of the first pace
+       # and the second one, they are alternated when deciphering a rail-encrypted string.
+       #
+       # Say we have the encrypted string "fgounbmtcieehkh" on 4 rails
+       #
+       # To find the distance between each character on the original railed
+       # string, we need to compute the extremes.
+       #
+       # The extremes always have a distance of `depth - 1`, multiplied by 2, no pairing.
+       #
+       # In the example, that would be : [(4 - 1) * 2, (4 - 1) * 2] => [6,6]
+       #
+       # For every rail in-between, the first distance is the largest absolute value
+       # of the difference between the current depth and the extremes, multiplied by 2.
+       #
+       # Its pair is the distance of maximum and the distance yielded by the previous
+       # calculation.
+       #
+       # In our example, that would be :
+       #
+       # Maximums : (4 - 1) * 2 = 3 * 2 => [6,6]
+       # In between : Distance for depth 2 : max(2 - 1, 4 - 2) => 2
+       # The calculation yields the couple [(2 * 2), 6 - 4] => [4, 2]
+       # The symmetric couple is reversed : [2, 4]
+       #
+       # In fine, the example yields the array : [[6,6], [4,2], [2,4], [6,6]]
+       #
+       # In the end, our string is read using the generated array
+       #
+       # SEE: `String::unrail` for how the array is used
+       private fun unrail_paces: Array[Couple[Int, Int]] do
+               var ret = new Array[Couple[Int,Int]].with_capacity(self)
+               var extremes = new Couple[Int, Int]((self - 1) * 2, (self - 1) * 2)
+               for i in [0..self[ do
+                       ret.add extremes
+               end
+               var mid = ((self.to_f)/2.0).floor.to_i
+               for i in [1 .. mid[ do
+                       var rd = i + 1
+                       var lodepth = self - rd
+                       var hidepth = (rd - self).abs
+                       var dd: Int
+                       if hidepth > lodepth then
+                               dd = hidepth * 2
+                       else
+                               dd = lodepth * 2
+                       end
+                       var cp = new Couple[Int, Int](dd, extremes.first-dd)
+                       var ccp = new Couple[Int, Int](extremes.first - dd, dd)
+
+                       ret[i] = cp
+                       ret[self - rd] = ccp
+               end
+               if not self.is_even then
+                       ret[mid] = new Couple[Int, Int](extremes.first/2, extremes.first/2)
+               end
+               return ret
+       end
+end