-
Notifications
You must be signed in to change notification settings - Fork 0
/
vigenere.py
73 lines (54 loc) · 2.72 KB
/
vigenere.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
from string import ascii_lowercase
class Vigenere:
"""
Encrypts and decrypts text using the [Vigenère cipher](https://en.wikipedia.org/wiki/Vigenère_cipher).
The alphabet is by default the lowercase Latin alphabet, but can be any
list of (unique) characters or strings.
"""
def __init__(self, alphabet=list(ascii_lowercase)):
if not isinstance(alphabet, list):
raise ValueError("Alphabet must be a list of characters or strings")
if len(set(alphabet)) != len(alphabet):
raise ValueError("Alphabet must not have duplicated symbols")
self.alphabet = alphabet
self.words = any(len(symbol) > 1 for symbol in alphabet)
def _transform(self, text, key, decrypting=False):
if key == "" or key == []:
raise ValueError("Key must not be empty")
if not isinstance(key, str) and not isinstance(key, list):
raise ValueError("Key must be a string or a list of strings")
if not isinstance(text, str) and not isinstance(text, list):
raise ValueError("Text must be a string or a list of strings")
transformed = []
for i, symbol in enumerate(text):
try:
symbol_idx = self.alphabet.index(symbol)
except ValueError:
raise ValueError("Symbols in text must be in the alphabet")
try:
key_symbol_idx = self.alphabet.index(key[i % len(key)])
except ValueError:
raise ValueError("Symbols in key must be in the alphabet")
idx = (
symbol_idx + (key_symbol_idx if not decrypting else -key_symbol_idx)
) % len(self.alphabet)
transformed.append(self.alphabet[idx])
return transformed if self.words else "".join(transformed)
def encrypt(self, text, key):
"""
Encrypts the message `text` using a Vigenère cipher with key `key`.
Both `text` and `key` must be either strings or lists of words (and both
must be the same type). The symbols (characters or words) in `text` and `key`
must all be present in the alphabet supplied when creating the instance. The
`key` must not be empty.
"""
return self._transform(text, key)
def decrypt(self, text, key):
"""
Decrypts the message `text` using a Vigenère cipher with key `key`.
Both `text` and `key` must be either strings or lists of words (and both
must be the same type). The symbols (characters or words) in `text` and `key`
must all be present in the alphabet supplied when creating the instance. The
`key` must not be empty.
"""
return self._transform(text, key, decrypting=True)