-
Notifications
You must be signed in to change notification settings - Fork 2
/
vigenere.erl
87 lines (69 loc) · 2.32 KB
/
vigenere.erl
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
-module(vigenere).
-export([crypt/2, decrypt/2]).
-define(IS_ULETTER(X), ((X >= $A) andalso (X =< $Z))).
-define(IS_LLETTER(X), ((X >= $a) andalso (X =< $z))).
-define(COUNT, ($Z - $A + 1)).
square(X, Y) when ?IS_ULETTER(X), ?IS_ULETTER(Y) ->
((X + Y - (2*$A)) rem ?COUNT) + $A.
resquare(X, Y) when ?IS_ULETTER(X), ?IS_ULETTER(Y) ->
((X - Y + (?COUNT * 2)) rem ?COUNT) + $A.
crypt(Str, Key) ->
Str2 = do_preprocess(Str, []),
Key2 = do_preprocess(Key, []),
do_crypt(fun square/2, Str2, Key2, Key2, []).
decrypt(Str, Key) ->
Str2 = do_preprocess(Str, []),
Key2 = do_preprocess(Key, []),
do_crypt(fun resquare/2, Str2, Key2, Key2, []).
%% @doc This version of the function is without predprocessing.
crypt2(Str, Key) ->
do_crypt(fun square/2, Str, Key, Key, []).
decrypt2(Str, Key) ->
do_crypt(fun resquare/2, Str, Key, Key, []).
do_preprocess([H|T], Acc)
when ?IS_ULETTER(H) ->
do_preprocess(T, [H|Acc]);
do_preprocess([H|T], Acc)
when ?IS_LLETTER(H) ->
NewH = $A - $a + H,
do_preprocess(T, [NewH|Acc]);
do_preprocess([_H|T], Acc) ->
do_preprocess(T, Acc);
do_preprocess([], Acc) ->
lists:reverse(Acc).
do_crypt(F, [SH|ST], [KH|KT], Key, Acc)
when ?IS_ULETTER(SH) ->
do_crypt(F, ST, KT, Key, [F(SH, KH)|Acc]);
% Skip if the letter is not in the upper case
do_crypt(F, [SH|ST], [_|KT], Key, Acc) ->
do_crypt(F, ST, KT, Key, [SH|Acc]);
do_crypt(F, [_|_]=Str, [], Key, Acc) ->
do_crypt(F, Str, Key, Key, Acc);
do_crypt(_, [], _, _, Acc) ->
lists:reverse(Acc).
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
square_test_() ->
F = fun square/2,
[?_assertEqual(F($A, $A), $A)
,?_assertEqual(F($A, $B), $B)
,?_assertEqual(F($Z, $Z), $Y)
,?_assertEqual(F($Z, $X), $W)
].
crypt_test_() ->
F = fun crypt/2,
[?_assertEqual(F("ATTACKATDAWN", "LEMON"), "LXFOPVEFRNHR")
].
crypt2_test_() ->
F = fun crypt2/2,
[?_assertEqual(F("CRYPTO IS SHORT FOR CRYPTOGRAPHY",
"ABCDAB CD ABCDA BCD ABCDABCDABCD"),
"CSASTP KV SIQUT GQU CSASTPIUAQJB")
].
decrypt_test_() ->
[?_assertEqual(decrypt(crypt("ATTACKATDAWN", "LEMON"), "LEMON"), "ATTACKATDAWN")
].
decrypt2_test_() ->
[?_assertEqual(decrypt2(crypt2("ATTACK AT DAWN", "LEMON"), "LEMON"), "ATTACK AT DAWN")
].
-endif.