X-Git-Url: http://nitlanguage.org diff --git a/lib/crypto.nit b/lib/crypto.nit index a84358f..357eb99 100644 --- a/lib/crypto.nit +++ b/lib/crypto.nit @@ -20,17 +20,17 @@ redef class Char # # 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' + # 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 + var val = code_point if is_upper then up = true val += 32 @@ -38,11 +38,11 @@ redef class Char val += x if val > 122 then val -= 26 if up then val -= 32 - return val.ascii + return val.code_point end end -redef class String +redef class Text # Performs a Rotation of `x` on each letter of self # # Works by replacing every character in `self` by its @@ -60,16 +60,15 @@ redef class String # 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." + # 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 + fun rot(x: Int): Text 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 @@ -82,16 +81,19 @@ redef class String # # 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..... + # This happens in-memory: + # + # ~~~raw + # 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 + # assert "fuckingbehemoth".railfence(4) == "fgounbmtcieehkh" + fun railfence(depth: Int): Text do var lines = new Array[FlatBuffer].with_capacity(depth) var up = false for i in [0..depth[ do @@ -125,10 +127,10 @@ redef class String return r.to_s end - # Transforms a rail-fence-encrypted String to its original + # Transforms a rail-fence-encrypted Text to its original # - # assert "fgounbmtcieehkh".unrail(4) == "fuckingbehemoth" - fun unrail(depth: Int): String do + # assert "fgounbmtcieehkh".unrail(4) == "fuckingbehemoth" + fun unrail(depth: Int): Text do var dots = "." * length var arr = new FlatBuffer.from(dots) var start = 0 @@ -152,6 +154,33 @@ redef class String end return arr.to_s end + + # Returns `self` xored with `key` + # + # The shortest of the two is cycled through until the longest has been + # completely xored. + # + # assert "goodmorning".xor(" ".to_bytes) == "GOODMORNING" + fun xor(key: SequenceRead[Byte]): Text do + var xored = new Bytes.with_capacity(bytelen.max(key.length)) + + var shortest: SequenceRead[Byte] + var longest: SequenceRead[Byte] + + if key.length > self.length then + shortest = self.to_bytes + longest = key + else + shortest = key + longest = self.to_bytes + end + + for i in longest.length.times do + xored.add(longest[i] ^ shortest[i % shortest.length]) + end + + return xored.to_s + end end redef class Int @@ -186,7 +215,7 @@ redef class Int # # In the end, our string is read using the generated array # - # SEE: `String::unrail` for how the array is used + # SEE: `Text::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)