0ef50dfd53e384479f5a8428c4760c673c1874ae
1 from szyfrow
.support
.utilities
import *
2 from szyfrow
.support
.language_models
import *
4 modular_division_table
= {
5 (multiplier
, (multiplier
* plaintext
) % 26): plaintext
6 for plaintext
in range(26)
7 for multiplier
in range(26)
11 def affine_encipher_letter(accented_letter
, multiplier
=1, adder
=0, one_based
=True):
12 """Encipher a letter, given a multiplier and adder
14 >>> cat(affine_encipher_letter(l, 3, 5, True) \
15 for l in string.ascii_letters)
16 'hknqtwzcfiloruxadgjmpsvybeHKNQTWZCFILORUXADGJMPSVYBE'
17 >>> cat(affine_encipher_letter(l, 3, 5, False) \
18 for l in string.ascii_letters)
19 'filoruxadgjmpsvybehknqtwzcFILORUXADGJMPSVYBEHKNQTWZC'
21 letter
= unaccent(accented_letter
)
22 if letter
in string
.ascii_letters
:
23 letter_number
= pos(letter
)
24 if one_based
: letter_number
+= 1
25 cipher_number
= (letter_number
* multiplier
+ adder
) % 26
26 if one_based
: cipher_number
-= 1
27 if letter
in string
.ascii_uppercase
:
28 return unpos(cipher_number
).upper()
30 return unpos(cipher_number
)
34 def affine_decipher_letter(letter
, multiplier
=1, adder
=0, one_based
=True):
35 """Encipher a letter, given a multiplier and adder
37 >>> cat(affine_decipher_letter(l, 3, 5, True) \
38 for l in 'hknqtwzcfiloruxadgjmpsvybeHKNQTWZCFILORUXADGJMPSVYBE')
39 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
40 >>> cat(affine_decipher_letter(l, 3, 5, False) \
41 for l in 'filoruxadgjmpsvybehknqtwzcFILORUXADGJMPSVYBEHKNQTWZC')
42 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
44 if letter
in string
.ascii_letters
:
45 cipher_number
= pos(letter
)
46 if one_based
: cipher_number
+= 1
47 # plaintext_number = (
48 # modular_division_table[multiplier]
49 # [(cipher_number - adder) % 26])
51 modular_division_table
[multiplier
, (cipher_number
- adder
) % 26]
53 if one_based
: plaintext_number
-= 1
54 if letter
in string
.ascii_uppercase
:
55 return unpos(plaintext_number
).upper()
57 return unpos(plaintext_number
)
61 def affine_encipher(message
, multiplier
=1, adder
=0, one_based
=True):
64 >>> affine_encipher('hours passed during which jerico tried every ' \
65 'trick he could think of', 15, 22, True)
66 'lmyfu bkuusd dyfaxw claol psfaom jfasd snsfg jfaoe ls omytd jlaxe mh'
68 enciphered
= [affine_encipher_letter(l
, multiplier
, adder
, one_based
)
70 return cat(enciphered
)
72 def affine_decipher(message
, multiplier
=1, adder
=0, one_based
=True):
75 >>> affine_decipher('lmyfu bkuusd dyfaxw claol psfaom jfasd snsfg ' \
76 'jfaoe ls omytd jlaxe mh', 15, 22, True)
77 'hours passed during which jerico tried every trick he could think of'
79 enciphered
= [affine_decipher_letter(l
, multiplier
, adder
, one_based
)
81 return cat(enciphered
)
85 def affine_break(message
, fitness
=Pletters
):
86 """Breaks an affine cipher using frequency analysis
88 >>> affine_break('lmyfu bkuusd dyfaxw claol psfaom jfasd snsfg jfaoe ls ' \
89 'omytd jlaxe mh jm bfmibj umis hfsul axubafkjamx. ls kffkxwsd jls ' \
90 'ofgbjmwfkiu olfmxmtmwaokttg jlsx ls kffkxwsd jlsi zg tsxwjl. jlsx ' \
91 'ls umfjsd jlsi zg hfsqysxog. ls dmmdtsd mx jls bats mh bkbsf. ls ' \
92 'bfmctsd kfmyxd jls lyj, mztanamyu xmc jm clm cku tmmeaxw kj lai ' \
93 'kxd clm ckuxj.') # doctest: +ELLIPSIS
94 ((15, 22, True), -340.601181913...)
96 sanitised_message
= sanitise(message
)
100 best_fit
= float("-inf")
101 for one_based
in [True, False]:
102 for multiplier
in [x
for x
in range(1, 26, 2) if x
!= 13]:
103 for adder
in range(26):
104 plaintext
= affine_decipher(sanitised_message
,
105 multiplier
, adder
, one_based
)
106 fit
= fitness(plaintext
)
109 best_multiplier
= multiplier
111 best_one_based
= one_based
113 return (best_multiplier
, best_adder
, best_one_based
), best_fit