1 """A set of ciphers with implementations for both enciphering and deciphering
2 them. See cipherbreak for automatic breaking of these ciphers
7 from language_models
import unaccent
, sanitise
10 modular_division_table
= [[0]*26 for _
in range(26)]
14 modular_division_table
[b
][c
] = a
17 def caesar_encipher_letter(accented_letter
, shift
):
18 """Encipher a letter, given a shift amount
20 >>> caesar_encipher_letter('a', 1)
22 >>> caesar_encipher_letter('a', 2)
24 >>> caesar_encipher_letter('b', 2)
26 >>> caesar_encipher_letter('x', 2)
28 >>> caesar_encipher_letter('y', 2)
30 >>> caesar_encipher_letter('z', 2)
32 >>> caesar_encipher_letter('z', -1)
34 >>> caesar_encipher_letter('a', -1)
36 >>> caesar_encipher_letter('A', 1)
38 >>> caesar_encipher_letter('é', 1)
41 letter
= unaccent(accented_letter
)
42 if letter
in string
.ascii_letters
:
43 if letter
in string
.ascii_uppercase
:
44 alphabet_start
= ord('A')
46 alphabet_start
= ord('a')
47 return chr(((ord(letter
) - alphabet_start
+ shift
) % 26) +
52 def caesar_decipher_letter(letter
, shift
):
53 """Decipher a letter, given a shift amount
55 >>> caesar_decipher_letter('b', 1)
57 >>> caesar_decipher_letter('b', 2)
60 return caesar_encipher_letter(letter
, -shift
)
62 def caesar_encipher(message
, shift
):
63 """Encipher a message with the Caesar cipher of given shift
65 >>> caesar_encipher('abc', 1)
67 >>> caesar_encipher('abc', 2)
69 >>> caesar_encipher('abcxyz', 2)
71 >>> caesar_encipher('ab cx yz', 2)
73 >>> caesar_encipher('Héllo World!', 2)
76 enciphered
= [caesar_encipher_letter(l
, shift
) for l
in message
]
77 return ''.join(enciphered
)
79 def caesar_decipher(message
, shift
):
80 """Decipher a message with the Caesar cipher of given shift
82 >>> caesar_decipher('bcd', 1)
84 >>> caesar_decipher('cde', 2)
86 >>> caesar_decipher('cd ez ab', 2)
88 >>> caesar_decipher('Jgnnq Yqtnf!', 2)
91 return caesar_encipher(message
, -shift
)
93 def affine_encipher_letter(accented_letter
, multiplier
=1, adder
=0,
95 """Encipher a letter, given a multiplier and adder
96 >>> ''.join([affine_encipher_letter(l, 3, 5, True) \
97 for l in string.ascii_uppercase])
98 'HKNQTWZCFILORUXADGJMPSVYBE'
99 >>> ''.join([affine_encipher_letter(l, 3, 5, False) \
100 for l in string.ascii_uppercase])
101 'FILORUXADGJMPSVYBEHKNQTWZC'
103 letter
= unaccent(accented_letter
)
104 if letter
in string
.ascii_letters
:
105 if letter
in string
.ascii_uppercase
:
106 alphabet_start
= ord('A')
108 alphabet_start
= ord('a')
109 letter_number
= ord(letter
) - alphabet_start
110 if one_based
: letter_number
+= 1
111 cipher_number
= (letter_number
* multiplier
+ adder
) % 26
112 if one_based
: cipher_number
-= 1
113 return chr(cipher_number
% 26 + alphabet_start
)
117 def affine_decipher_letter(letter
, multiplier
=1, adder
=0, one_based
=True):
118 """Encipher a letter, given a multiplier and adder
120 >>> ''.join([affine_decipher_letter(l, 3, 5, True) \
121 for l in 'HKNQTWZCFILORUXADGJMPSVYBE'])
122 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
123 >>> ''.join([affine_decipher_letter(l, 3, 5, False) \
124 for l in 'FILORUXADGJMPSVYBEHKNQTWZC'])
125 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
127 if letter
in string
.ascii_letters
:
128 if letter
in string
.ascii_uppercase
:
129 alphabet_start
= ord('A')
131 alphabet_start
= ord('a')
132 cipher_number
= ord(letter
) - alphabet_start
133 if one_based
: cipher_number
+= 1
135 modular_division_table
[multiplier
]
136 [(cipher_number
- adder
) % 26]
138 if one_based
: plaintext_number
-= 1
139 return chr(plaintext_number
% 26 + alphabet_start
)
143 def affine_encipher(message
, multiplier
=1, adder
=0, one_based
=True):
144 """Encipher a message
146 >>> affine_encipher('hours passed during which jerico tried every ' \
147 'trick he could think of', 15, 22, True)
148 'lmyfu bkuusd dyfaxw claol psfaom jfasd snsfg jfaoe ls omytd jlaxe mh'
150 enciphered
= [affine_encipher_letter(l
, multiplier
, adder
, one_based
)
152 return ''.join(enciphered
)
154 def affine_decipher(message
, multiplier
=1, adder
=0, one_based
=True):
155 """Decipher a message
157 >>> affine_decipher('lmyfu bkuusd dyfaxw claol psfaom jfasd snsfg ' \
158 'jfaoe ls omytd jlaxe mh', 15, 22, True)
159 'hours passed during which jerico tried every trick he could think of'
161 enciphered
= [affine_decipher_letter(l
, multiplier
, adder
, one_based
)
163 return ''.join(enciphered
)
167 if __name__
== "__main__":