-
Notifications
You must be signed in to change notification settings - Fork 0
/
caesar.fsx
52 lines (40 loc) · 1.72 KB
/
caesar.fsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
(*
Caesar cipher -
Implement a Caesar cipher, both encoding and decoding.
The key is an integer from 1 to 25. This cipher rotates the letters of the alphabet (A to Z).
The encoding replaces each letter with the 1st to 25th next letter in the alphabet (wrapping Z to A).
So key 2 encrypts "HI" to "JK", but key 20 encrypts "HI" to "BC".
This simple "monoalphabetic substitution cipher" provides almost no security, because an attacker who has the encoded message
can either use frequency analysis to guess the key, or just try all 25 keys.
changed requirements:
- shift can be any number, not only 1 - 25
*)
open System
let alphabet = [| 'A' .. 'Z' |]
let tryGetIndex c =
let idx = alphabet
|> Array.tryFindIndex (fun t -> t = (Char.ToUpper c))
(c, idx)
// own modulo operation because f# % doesn't work right for us if we're handling negative numbers
// f#: -3 % 26 -> -3
// 'ours': modulo -3 26 -> 23
// taken from here: http://gettingsharper.de/2012/02/28/how-to-implement-a-mathematically-correct-modulus-operator-in-f/
let modulo n m = ((n % m) + m) % m
let shiftIdx idx shift =
let newIdx = idx + shift
modulo newIdx alphabet.Length
let encryptIdx idx shift =
shiftIdx idx shift
let decryptIdx idx shift =
shiftIdx idx (-shift)
let getShifted shift shiftOperation charIdx =
match charIdx with
| _, Some idx -> alphabet.[shiftOperation idx shift]
| c, None -> c
let operateCaesar operation shift text =
text
|> String.map (tryGetIndex >> getShifted shift operation)
let encryptcaesar = operateCaesar encryptIdx
let decryptcaesar = operateCaesar decryptIdx
let enc = "hello world" |> encryptcaesar 13
let dec = enc |> decryptcaesar 13