-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvigeneres.py
165 lines (138 loc) · 5.49 KB
/
vigeneres.py
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
import string
import sys
import vigtools
def vigere(t, k, is_encode):
"""
A Cypher function that takes a message and encodes it based on a given key.
It will shift the alphabet of each character in the message based on the next character
in the key eg:
Message: hello world! | Static key: weld
Key: weldw eldwe
Encoded: diwok azuhh!
"""
# Safety check arguments:
chk_args = vigtools.checkargs(t, k)
if chk_args != 0:
sys.exit()
msg = str(t.lower())
# Convert key to a list of unique sub-keys:
key = vigtools.uniqify(k.lower())
# Holds the index of the current sub-key.
key_index = 0
# Create a dictionary of each alphabet character 0-25.
alphabet = list(string.ascii_lowercase)
# Append each encoded character here:
result = ''
for char in msg:
# Negative 1 always represents a non-alpha char.
num = -1
# Get the value of the current character based on its order in the alphabet.
try:
num = alphabet.index(char)
except ValueError:
num = -1
# Get the amount of places to shift by when encoding, based on the current sub-key.
total_shift = 0
# If the user has asked to encode text:
if is_encode:
# Find the positive shift of the alphabet character:
if char in string.ascii_lowercase:
total_shift = num + alphabet.index(key[key_index])
# If the shifted value is outside the alphabet range, overflow to the beginning:
if total_shift > 25:
total_shift -= 26
# Otherwise the user has asked for decoding:
else:
# Find the negative shift of the alphabet character:
if char in string.ascii_lowercase:
total_shift = num - alphabet.index(key[key_index])
# If the shifted value is outside the alphabet range, overflow to the end:
if total_shift < 0:
total_shift += 26
# Add the current char if its not in the alphabet...
if num == -1:
result = result + char
# ...or the encoded/decoded char if it is.
else:
result = result + alphabet[total_shift]
# Increment the counter of the index of a sub-key, unless it is the last sub-key.
if key_index == len(key)-1:
key_index = 0
elif num != -1:
key_index += 1
# Finally, return the encoded result:
return result
def evaluate():
"""
A debugging function to check if theres any deviation between the encodev function and
a previously evaluated encoding. This uses a phrase that contains all letters of the
alphabet.
"""
text = 'The quick brown fox jumps over the lazy dog.'
key = 'doggone'
# From http://planetcalc.com/2468/:
expected = 'wvk dylqq ovrkt ssa xaztv cbrv wvk yecm jbk.'
# Run the cypher:
result = vigere(text, key, True)
# Check the result against the expected encoded message:
alphabet = list(string.ascii_lowercase)
# The current index for check between the characters of
# the expected and resulting messages.
index = 0
# If this stays at zero, print that the test was successful.
number_of_errors = 0
# Check each letter in the expected message against its corresponding
# letter in the result.
for e in list(expected):
if e in alphabet:
# Get the value of the current characters based on its order in
# the alphabet.
expected_number = alphabet.index(e)
result_number = alphabet.index(list(result)[index])
# Calculate the difference:
difference = expected_number - result_number
# Print only if theres an error:
if difference != 0:
number_of_errors += 1
# Print a header before any of the errors, if at least one exists.
if number_of_errors == 1:
print('Errors: ')
#... then print the difference of the characters' values.
print(' ' + e + ' : ' + list(result)[index] + ' Difference in Position: ' + str(difference))
# Check the next corresponding character.
index += 1
# Print success if there were no errors
if number_of_errors == 0:
print('Expected: ' + expected + '\nResult: ' + result)
print('Cypher encodes as expected.')
if __name__ == '__main__':
if sys.argv[1] == 'encode':
# Check if the key contains non-alpha characters:
for c in sys.argv[3]:
if c not in list(string.ascii_letters):
print('Key can only contain alphabetic characters.')
sys.exit()
# Otherwise, run the cypher encoder:
coded = vigere(sys.argv[2], sys.argv[3], True)
print(coded)
sys.exit()
elif sys.argv[1] == 'decode':
# Check if the key contains non-alpha characters:
for c in sys.argv[3]:
if c not in list(string.ascii_letters):
print('Key can only contain alphabetic characters.')
sys.exit()
# Otherwise, run the cypher decoder:
coded = vigere(sys.argv[2], sys.argv[3], False)
print(coded)
sys.exit()
elif sys.argv[1] == 'test':
evaluate()
sys.exit()
else:
print(""" Useage:\n
vigeners.py encode <message> <key>\n
decode <encodedmsg> <key>\n
test\n
\n
""")