-
-
Notifications
You must be signed in to change notification settings - Fork 46k
/
rail_fence_cipher.py
102 lines (79 loc) · 3.09 KB
/
rail_fence_cipher.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
"""https://en.wikipedia.org/wiki/Rail_fence_cipher"""
def encrypt(input_string: str, key: int) -> str:
"""
Shuffles the character of a string by placing each of them
in a grid (the height is dependent on the key) in a zigzag
formation and reading it left to right.
>>> encrypt("Hello World", 4)
'HWe olordll'
>>> encrypt("This is a message", 0)
Traceback (most recent call last):
...
ValueError: Height of grid can't be 0 or negative
>>> encrypt(b"This is a byte string", 5)
Traceback (most recent call last):
...
TypeError: sequence item 0: expected str instance, int found
"""
temp_grid: list[list[str]] = [[] for _ in range(key)]
lowest = key - 1
if key <= 0:
raise ValueError("Height of grid can't be 0 or negative")
if key == 1 or len(input_string) <= key:
return input_string
for position, character in enumerate(input_string):
num = position % (lowest * 2) # puts it in bounds
num = min(num, lowest * 2 - num) # creates zigzag pattern
temp_grid[num].append(character)
grid = ["".join(row) for row in temp_grid]
output_string = "".join(grid)
return output_string
def decrypt(input_string: str, key: int) -> str:
"""
Generates a template based on the key and fills it in with
the characters of the input string and then reading it in
a zigzag formation.
>>> decrypt("HWe olordll", 4)
'Hello World'
>>> decrypt("This is a message", -10)
Traceback (most recent call last):
...
ValueError: Height of grid can't be 0 or negative
>>> decrypt("My key is very big", 100)
'My key is very big'
"""
grid = []
lowest = key - 1
if key <= 0:
raise ValueError("Height of grid can't be 0 or negative")
if key == 1:
return input_string
temp_grid: list[list[str]] = [[] for _ in range(key)] # generates template
for position in range(len(input_string)):
num = position % (lowest * 2) # puts it in bounds
num = min(num, lowest * 2 - num) # creates zigzag pattern
temp_grid[num].append("*")
counter = 0
for row in temp_grid: # fills in the characters
splice = input_string[counter : counter + len(row)]
grid.append(list(splice))
counter += len(row)
output_string = "" # reads as zigzag
for position in range(len(input_string)):
num = position % (lowest * 2) # puts it in bounds
num = min(num, lowest * 2 - num) # creates zigzag pattern
output_string += grid[num][0]
grid[num].pop(0)
return output_string
def bruteforce(input_string: str) -> dict[int, str]:
"""Uses decrypt function by guessing every key
>>> bruteforce("HWe olordll")[4]
'Hello World'
"""
results = {}
for key_guess in range(1, len(input_string)): # tries every key
results[key_guess] = decrypt(input_string, key_guess)
return results
if __name__ == "__main__":
import doctest
doctest.testmod()