mirror of
https://github.com/TheAlgorithms/Python.git
synced 2025-01-30 14:13:44 +00:00
Fix sphinx/build_docs warnings for ciphers (#12485)
* Fix sphinx/build_docs warnings for ciphers * Fix
This commit is contained in:
parent
94b3777936
commit
f45e392cf6
|
@ -1,5 +1,6 @@
|
||||||
"""
|
"""
|
||||||
https://en.wikipedia.org/wiki/Autokey_cipher
|
https://en.wikipedia.org/wiki/Autokey_cipher
|
||||||
|
|
||||||
An autokey cipher (also known as the autoclave cipher) is a cipher that
|
An autokey cipher (also known as the autoclave cipher) is a cipher that
|
||||||
incorporates the message (the plaintext) into the key.
|
incorporates the message (the plaintext) into the key.
|
||||||
The key is generated from the message in some automated fashion,
|
The key is generated from the message in some automated fashion,
|
||||||
|
@ -10,8 +11,9 @@ by adding a short primer key to the front of the message.
|
||||||
|
|
||||||
def encrypt(plaintext: str, key: str) -> str:
|
def encrypt(plaintext: str, key: str) -> str:
|
||||||
"""
|
"""
|
||||||
Encrypt a given plaintext (string) and key (string), returning the
|
Encrypt a given `plaintext` (string) and `key` (string), returning the
|
||||||
encrypted ciphertext.
|
encrypted ciphertext.
|
||||||
|
|
||||||
>>> encrypt("hello world", "coffee")
|
>>> encrypt("hello world", "coffee")
|
||||||
'jsqqs avvwo'
|
'jsqqs avvwo'
|
||||||
>>> encrypt("coffee is good as python", "TheAlgorithms")
|
>>> encrypt("coffee is good as python", "TheAlgorithms")
|
||||||
|
@ -74,8 +76,9 @@ def encrypt(plaintext: str, key: str) -> str:
|
||||||
|
|
||||||
def decrypt(ciphertext: str, key: str) -> str:
|
def decrypt(ciphertext: str, key: str) -> str:
|
||||||
"""
|
"""
|
||||||
Decrypt a given ciphertext (string) and key (string), returning the decrypted
|
Decrypt a given `ciphertext` (string) and `key` (string), returning the decrypted
|
||||||
ciphertext.
|
ciphertext.
|
||||||
|
|
||||||
>>> decrypt("jsqqs avvwo", "coffee")
|
>>> decrypt("jsqqs avvwo", "coffee")
|
||||||
'hello world'
|
'hello world'
|
||||||
>>> decrypt("vvjfpk wj ohvp su ddylsv", "TheAlgorithms")
|
>>> decrypt("vvjfpk wj ohvp su ddylsv", "TheAlgorithms")
|
||||||
|
|
|
@ -7,24 +7,29 @@ def encrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
|
||||||
"""
|
"""
|
||||||
encrypt
|
encrypt
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Encodes a given string with the caesar cipher and returns the encoded
|
Encodes a given string with the caesar cipher and returns the encoded
|
||||||
message
|
message
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
-----------
|
-----------
|
||||||
* input_string: the plain-text that needs to be encoded
|
|
||||||
* key: the number of letters to shift the message by
|
* `input_string`: the plain-text that needs to be encoded
|
||||||
|
* `key`: the number of letters to shift the message by
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
* alphabet (None): the alphabet used to encode the cipher, if not
|
|
||||||
|
* `alphabet` (``None``): the alphabet used to encode the cipher, if not
|
||||||
specified, the standard english alphabet with upper and lowercase
|
specified, the standard english alphabet with upper and lowercase
|
||||||
letters is used
|
letters is used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* A string containing the encoded cipher-text
|
* A string containing the encoded cipher-text
|
||||||
|
|
||||||
More on the caesar cipher
|
More on the caesar cipher
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
The caesar cipher is named after Julius Caesar who used it when sending
|
The caesar cipher is named after Julius Caesar who used it when sending
|
||||||
secret military messages to his troops. This is a simple substitution cipher
|
secret military messages to his troops. This is a simple substitution cipher
|
||||||
where every character in the plain-text is shifted by a certain number known
|
where every character in the plain-text is shifted by a certain number known
|
||||||
|
@ -32,26 +37,28 @@ def encrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Say we have the following message:
|
Say we have the following message:
|
||||||
"Hello, captain"
|
``Hello, captain``
|
||||||
|
|
||||||
And our alphabet is made up of lower and uppercase letters:
|
And our alphabet is made up of lower and uppercase letters:
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ``
|
||||||
|
|
||||||
And our shift is "2"
|
And our shift is ``2``
|
||||||
|
|
||||||
We can then encode the message, one letter at a time. "H" would become "J",
|
We can then encode the message, one letter at a time. ``H`` would become ``J``,
|
||||||
since "J" is two letters away, and so on. If the shift is ever two large, or
|
since ``J`` is two letters away, and so on. If the shift is ever two large, or
|
||||||
our letter is at the end of the alphabet, we just start at the beginning
|
our letter is at the end of the alphabet, we just start at the beginning
|
||||||
("Z" would shift to "a" then "b" and so on).
|
(``Z`` would shift to ``a`` then ``b`` and so on).
|
||||||
|
|
||||||
Our final message would be "Jgnnq, ecrvckp"
|
Our final message would be ``Jgnnq, ecrvckp``
|
||||||
|
|
||||||
Further reading
|
Further reading
|
||||||
===============
|
===============
|
||||||
|
|
||||||
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
|
||||||
Doctests
|
Doctests
|
||||||
========
|
========
|
||||||
|
|
||||||
>>> encrypt('The quick brown fox jumps over the lazy dog', 8)
|
>>> encrypt('The quick brown fox jumps over the lazy dog', 8)
|
||||||
'bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo'
|
'bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo'
|
||||||
|
|
||||||
|
@ -85,23 +92,28 @@ def decrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
|
||||||
"""
|
"""
|
||||||
decrypt
|
decrypt
|
||||||
=======
|
=======
|
||||||
|
|
||||||
Decodes a given string of cipher-text and returns the decoded plain-text
|
Decodes a given string of cipher-text and returns the decoded plain-text
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
-----------
|
-----------
|
||||||
* input_string: the cipher-text that needs to be decoded
|
|
||||||
* key: the number of letters to shift the message backwards by to decode
|
* `input_string`: the cipher-text that needs to be decoded
|
||||||
|
* `key`: the number of letters to shift the message backwards by to decode
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
* alphabet (None): the alphabet used to decode the cipher, if not
|
|
||||||
|
* `alphabet` (``None``): the alphabet used to decode the cipher, if not
|
||||||
specified, the standard english alphabet with upper and lowercase
|
specified, the standard english alphabet with upper and lowercase
|
||||||
letters is used
|
letters is used
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
* A string containing the decoded plain-text
|
* A string containing the decoded plain-text
|
||||||
|
|
||||||
More on the caesar cipher
|
More on the caesar cipher
|
||||||
=========================
|
=========================
|
||||||
|
|
||||||
The caesar cipher is named after Julius Caesar who used it when sending
|
The caesar cipher is named after Julius Caesar who used it when sending
|
||||||
secret military messages to his troops. This is a simple substitution cipher
|
secret military messages to his troops. This is a simple substitution cipher
|
||||||
where very character in the plain-text is shifted by a certain number known
|
where very character in the plain-text is shifted by a certain number known
|
||||||
|
@ -110,27 +122,29 @@ def decrypt(input_string: str, key: int, alphabet: str | None = None) -> str:
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
Say we have the following cipher-text:
|
Say we have the following cipher-text:
|
||||||
"Jgnnq, ecrvckp"
|
``Jgnnq, ecrvckp``
|
||||||
|
|
||||||
And our alphabet is made up of lower and uppercase letters:
|
And our alphabet is made up of lower and uppercase letters:
|
||||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
``abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ``
|
||||||
|
|
||||||
And our shift is "2"
|
And our shift is ``2``
|
||||||
|
|
||||||
To decode the message, we would do the same thing as encoding, but in
|
To decode the message, we would do the same thing as encoding, but in
|
||||||
reverse. The first letter, "J" would become "H" (remember: we are decoding)
|
reverse. The first letter, ``J`` would become ``H`` (remember: we are decoding)
|
||||||
because "H" is two letters in reverse (to the left) of "J". We would
|
because ``H`` is two letters in reverse (to the left) of ``J``. We would
|
||||||
continue doing this. A letter like "a" would shift back to the end of
|
continue doing this. A letter like ``a`` would shift back to the end of
|
||||||
the alphabet, and would become "Z" or "Y" and so on.
|
the alphabet, and would become ``Z`` or ``Y`` and so on.
|
||||||
|
|
||||||
Our final message would be "Hello, captain"
|
Our final message would be ``Hello, captain``
|
||||||
|
|
||||||
Further reading
|
Further reading
|
||||||
===============
|
===============
|
||||||
|
|
||||||
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
|
||||||
Doctests
|
Doctests
|
||||||
========
|
========
|
||||||
|
|
||||||
>>> decrypt('bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo', 8)
|
>>> decrypt('bpm yCqks jzwEv nwF rCuxA wDmz Bpm tiHG lwo', 8)
|
||||||
'The quick brown fox jumps over the lazy dog'
|
'The quick brown fox jumps over the lazy dog'
|
||||||
|
|
||||||
|
@ -150,41 +164,44 @@ def brute_force(input_string: str, alphabet: str | None = None) -> dict[int, str
|
||||||
"""
|
"""
|
||||||
brute_force
|
brute_force
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Returns all the possible combinations of keys and the decoded strings in the
|
Returns all the possible combinations of keys and the decoded strings in the
|
||||||
form of a dictionary
|
form of a dictionary
|
||||||
|
|
||||||
Parameters:
|
Parameters:
|
||||||
-----------
|
-----------
|
||||||
* input_string: the cipher-text that needs to be used during brute-force
|
|
||||||
|
* `input_string`: the cipher-text that needs to be used during brute-force
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
* alphabet: (None): the alphabet used to decode the cipher, if not
|
|
||||||
|
* `alphabet` (``None``): the alphabet used to decode the cipher, if not
|
||||||
specified, the standard english alphabet with upper and lowercase
|
specified, the standard english alphabet with upper and lowercase
|
||||||
letters is used
|
letters is used
|
||||||
|
|
||||||
More about brute force
|
More about brute force
|
||||||
======================
|
======================
|
||||||
|
|
||||||
Brute force is when a person intercepts a message or password, not knowing
|
Brute force is when a person intercepts a message or password, not knowing
|
||||||
the key and tries every single combination. This is easy with the caesar
|
the key and tries every single combination. This is easy with the caesar
|
||||||
cipher since there are only all the letters in the alphabet. The more
|
cipher since there are only all the letters in the alphabet. The more
|
||||||
complex the cipher, the larger amount of time it will take to do brute force
|
complex the cipher, the larger amount of time it will take to do brute force
|
||||||
|
|
||||||
Ex:
|
Ex:
|
||||||
Say we have a 5 letter alphabet (abcde), for simplicity and we intercepted the
|
Say we have a ``5`` letter alphabet (``abcde``), for simplicity and we intercepted
|
||||||
following message:
|
the following message: ``dbc``,
|
||||||
|
|
||||||
"dbc"
|
|
||||||
|
|
||||||
we could then just write out every combination:
|
we could then just write out every combination:
|
||||||
ecd... and so on, until we reach a combination that makes sense:
|
``ecd``... and so on, until we reach a combination that makes sense:
|
||||||
"cab"
|
``cab``
|
||||||
|
|
||||||
Further reading
|
Further reading
|
||||||
===============
|
===============
|
||||||
|
|
||||||
* https://en.wikipedia.org/wiki/Brute_force
|
* https://en.wikipedia.org/wiki/Brute_force
|
||||||
|
|
||||||
Doctests
|
Doctests
|
||||||
========
|
========
|
||||||
|
|
||||||
>>> brute_force("jFyuMy xIH'N vLONy zILwy Gy!")[20]
|
>>> brute_force("jFyuMy xIH'N vLONy zILwy Gy!")[20]
|
||||||
"Please don't brute force me!"
|
"Please don't brute force me!"
|
||||||
|
|
||||||
|
|
|
@ -11,32 +11,30 @@ def decrypt_caesar_with_chi_squared(
|
||||||
"""
|
"""
|
||||||
Basic Usage
|
Basic Usage
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Arguments:
|
Arguments:
|
||||||
* ciphertext (str): the text to decode (encoded with the caesar cipher)
|
* `ciphertext` (str): the text to decode (encoded with the caesar cipher)
|
||||||
|
|
||||||
Optional Arguments:
|
Optional Arguments:
|
||||||
* cipher_alphabet (list): the alphabet used for the cipher (each letter is
|
* `cipher_alphabet` (list): the alphabet used for the cipher (each letter is
|
||||||
a string separated by commas)
|
a string separated by commas)
|
||||||
* frequencies_dict (dict): a dictionary of word frequencies where keys are
|
* `frequencies_dict` (dict): a dictionary of word frequencies where keys are
|
||||||
the letters and values are a percentage representation of the frequency as
|
the letters and values are a percentage representation of the frequency as
|
||||||
a decimal/float
|
a decimal/float
|
||||||
* case_sensitive (bool): a boolean value: True if the case matters during
|
* `case_sensitive` (bool): a boolean value: ``True`` if the case matters during
|
||||||
decryption, False if it doesn't
|
decryption, ``False`` if it doesn't
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
* A tuple in the form of:
|
* A tuple in the form of:
|
||||||
(
|
(`most_likely_cipher`, `most_likely_cipher_chi_squared_value`,
|
||||||
most_likely_cipher,
|
`decoded_most_likely_cipher`)
|
||||||
most_likely_cipher_chi_squared_value,
|
|
||||||
decoded_most_likely_cipher
|
|
||||||
)
|
|
||||||
|
|
||||||
where...
|
where...
|
||||||
- most_likely_cipher is an integer representing the shift of the smallest
|
- `most_likely_cipher` is an integer representing the shift of the smallest
|
||||||
chi-squared statistic (most likely key)
|
chi-squared statistic (most likely key)
|
||||||
- most_likely_cipher_chi_squared_value is a float representing the
|
- `most_likely_cipher_chi_squared_value` is a float representing the
|
||||||
chi-squared statistic of the most likely shift
|
chi-squared statistic of the most likely shift
|
||||||
- decoded_most_likely_cipher is a string with the decoded cipher
|
- `decoded_most_likely_cipher` is a string with the decoded cipher
|
||||||
(decoded by the most_likely_cipher key)
|
(decoded by the most_likely_cipher key)
|
||||||
|
|
||||||
|
|
||||||
|
@ -45,37 +43,40 @@ def decrypt_caesar_with_chi_squared(
|
||||||
|
|
||||||
The caesar cipher
|
The caesar cipher
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The caesar cipher is a very insecure encryption algorithm, however it has
|
The caesar cipher is a very insecure encryption algorithm, however it has
|
||||||
been used since Julius Caesar. The cipher is a simple substitution cipher
|
been used since Julius Caesar. The cipher is a simple substitution cipher
|
||||||
where each character in the plain text is replaced by a character in the
|
where each character in the plain text is replaced by a character in the
|
||||||
alphabet a certain number of characters after the original character. The
|
alphabet a certain number of characters after the original character. The
|
||||||
number of characters away is called the shift or key. For example:
|
number of characters away is called the shift or key. For example:
|
||||||
|
|
||||||
Plain text: hello
|
| Plain text: ``hello``
|
||||||
Key: 1
|
| Key: ``1``
|
||||||
Cipher text: ifmmp
|
| Cipher text: ``ifmmp``
|
||||||
(each letter in hello has been shifted one to the right in the eng. alphabet)
|
| (each letter in ``hello`` has been shifted one to the right in the eng. alphabet)
|
||||||
|
|
||||||
As you can imagine, this doesn't provide lots of security. In fact
|
As you can imagine, this doesn't provide lots of security. In fact
|
||||||
decrypting ciphertext by brute-force is extremely easy even by hand. However
|
decrypting ciphertext by brute-force is extremely easy even by hand. However
|
||||||
one way to do that is the chi-squared test.
|
one way to do that is the chi-squared test.
|
||||||
|
|
||||||
The chi-squared test
|
The chi-squared test
|
||||||
-------------------
|
--------------------
|
||||||
|
|
||||||
Each letter in the english alphabet has a frequency, or the amount of times
|
Each letter in the english alphabet has a frequency, or the amount of times
|
||||||
it shows up compared to other letters (usually expressed as a decimal
|
it shows up compared to other letters (usually expressed as a decimal
|
||||||
representing the percentage likelihood). The most common letter in the
|
representing the percentage likelihood). The most common letter in the
|
||||||
english language is "e" with a frequency of 0.11162 or 11.162%. The test is
|
english language is ``e`` with a frequency of ``0.11162`` or ``11.162%``.
|
||||||
completed in the following fashion.
|
The test is completed in the following fashion.
|
||||||
|
|
||||||
1. The ciphertext is decoded in a brute force way (every combination of the
|
1. The ciphertext is decoded in a brute force way (every combination of the
|
||||||
26 possible combinations)
|
``26`` possible combinations)
|
||||||
2. For every combination, for each letter in the combination, the average
|
2. For every combination, for each letter in the combination, the average
|
||||||
amount of times the letter should appear the message is calculated by
|
amount of times the letter should appear the message is calculated by
|
||||||
multiplying the total number of characters by the frequency of the letter
|
multiplying the total number of characters by the frequency of the letter.
|
||||||
|
|
||||||
For example:
|
| For example:
|
||||||
In a message of 100 characters, e should appear around 11.162 times.
|
| In a message of ``100`` characters, ``e`` should appear around ``11.162``
|
||||||
|
times.
|
||||||
|
|
||||||
3. Then, to calculate the margin of error (the amount of times the letter
|
3. Then, to calculate the margin of error (the amount of times the letter
|
||||||
SHOULD appear with the amount of times the letter DOES appear), we use
|
SHOULD appear with the amount of times the letter DOES appear), we use
|
||||||
|
@ -84,10 +85,12 @@ def decrypt_caesar_with_chi_squared(
|
||||||
Let:
|
Let:
|
||||||
- n be the number of times the letter actually appears
|
- n be the number of times the letter actually appears
|
||||||
- p be the predicted value of the number of times the letter should
|
- p be the predicted value of the number of times the letter should
|
||||||
appear (see #2)
|
appear (see item ``2``)
|
||||||
- let v be the chi-squared test result (referred to here as chi-squared
|
- let v be the chi-squared test result (referred to here as chi-squared
|
||||||
value/statistic)
|
value/statistic)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
(n - p)^2
|
(n - p)^2
|
||||||
--------- = v
|
--------- = v
|
||||||
p
|
p
|
||||||
|
@ -98,16 +101,16 @@ def decrypt_caesar_with_chi_squared(
|
||||||
to be the decoded answer.
|
to be the decoded answer.
|
||||||
|
|
||||||
Further Reading
|
Further Reading
|
||||||
================
|
===============
|
||||||
|
|
||||||
* http://practicalcryptography.com/cryptanalysis/text-characterisation/chi-squared-
|
* http://practicalcryptography.com/cryptanalysis/text-characterisation/chi-squared-statistic/
|
||||||
statistic/
|
|
||||||
* https://en.wikipedia.org/wiki/Letter_frequency
|
* https://en.wikipedia.org/wiki/Letter_frequency
|
||||||
* https://en.wikipedia.org/wiki/Chi-squared_test
|
* https://en.wikipedia.org/wiki/Chi-squared_test
|
||||||
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
* https://en.m.wikipedia.org/wiki/Caesar_cipher
|
||||||
|
|
||||||
Doctests
|
Doctests
|
||||||
========
|
========
|
||||||
|
|
||||||
>>> decrypt_caesar_with_chi_squared(
|
>>> decrypt_caesar_with_chi_squared(
|
||||||
... 'dof pz aol jhlzhy jpwoly zv wvwbshy? pa pz avv lhzf av jyhjr!'
|
... 'dof pz aol jhlzhy jpwoly zv wvwbshy? pa pz avv lhzf av jyhjr!'
|
||||||
... ) # doctest: +NORMALIZE_WHITESPACE
|
... ) # doctest: +NORMALIZE_WHITESPACE
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
"""
|
"""
|
||||||
Wikipedia: https://en.wikipedia.org/wiki/Enigma_machine
|
| Wikipedia: https://en.wikipedia.org/wiki/Enigma_machine
|
||||||
Video explanation: https://youtu.be/QwQVMqfoB2E
|
| Video explanation: https://youtu.be/QwQVMqfoB2E
|
||||||
Also check out Numberphile's and Computerphile's videos on this topic
|
| Also check out Numberphile's and Computerphile's videos on this topic
|
||||||
|
|
||||||
This module contains function 'enigma' which emulates
|
This module contains function ``enigma`` which emulates
|
||||||
the famous Enigma machine from WWII.
|
the famous Enigma machine from WWII.
|
||||||
|
|
||||||
Module includes:
|
Module includes:
|
||||||
- enigma function
|
|
||||||
|
- ``enigma`` function
|
||||||
- showcase of function usage
|
- showcase of function usage
|
||||||
- 9 randomly generated rotors
|
- ``9`` randomly generated rotors
|
||||||
- reflector (aka static rotor)
|
- reflector (aka static rotor)
|
||||||
- original alphabet
|
- original alphabet
|
||||||
|
|
||||||
|
@ -73,7 +75,7 @@ def _validator(
|
||||||
rotpos: RotorPositionT, rotsel: RotorSelectionT, pb: str
|
rotpos: RotorPositionT, rotsel: RotorSelectionT, pb: str
|
||||||
) -> tuple[RotorPositionT, RotorSelectionT, dict[str, str]]:
|
) -> tuple[RotorPositionT, RotorSelectionT, dict[str, str]]:
|
||||||
"""
|
"""
|
||||||
Checks if the values can be used for the 'enigma' function
|
Checks if the values can be used for the ``enigma`` function
|
||||||
|
|
||||||
>>> _validator((1,1,1), (rotor1, rotor2, rotor3), 'POLAND')
|
>>> _validator((1,1,1), (rotor1, rotor2, rotor3), 'POLAND')
|
||||||
((1, 1, 1), ('EGZWVONAHDCLFQMSIPJBYUKXTR', 'FOBHMDKEXQNRAULPGSJVTYICZW', \
|
((1, 1, 1), ('EGZWVONAHDCLFQMSIPJBYUKXTR', 'FOBHMDKEXQNRAULPGSJVTYICZW', \
|
||||||
|
@ -83,7 +85,7 @@ def _validator(
|
||||||
:param rotpos: rotor_positon
|
:param rotpos: rotor_positon
|
||||||
:param rotsel: rotor_selection
|
:param rotsel: rotor_selection
|
||||||
:param pb: plugb -> validated and transformed
|
:param pb: plugb -> validated and transformed
|
||||||
:return: (rotpos, rotsel, pb)
|
:return: (`rotpos`, `rotsel`, `pb`)
|
||||||
"""
|
"""
|
||||||
# Checks if there are 3 unique rotors
|
# Checks if there are 3 unique rotors
|
||||||
|
|
||||||
|
@ -118,9 +120,10 @@ def _plugboard(pbstring: str) -> dict[str, str]:
|
||||||
>>> _plugboard('POLAND')
|
>>> _plugboard('POLAND')
|
||||||
{'P': 'O', 'O': 'P', 'L': 'A', 'A': 'L', 'N': 'D', 'D': 'N'}
|
{'P': 'O', 'O': 'P', 'L': 'A', 'A': 'L', 'N': 'D', 'D': 'N'}
|
||||||
|
|
||||||
In the code, 'pb' stands for 'plugboard'
|
In the code, ``pb`` stands for ``plugboard``
|
||||||
|
|
||||||
Pairs can be separated by spaces
|
Pairs can be separated by spaces
|
||||||
|
|
||||||
:param pbstring: string containing plugboard setting for the Enigma machine
|
:param pbstring: string containing plugboard setting for the Enigma machine
|
||||||
:return: dictionary containing converted pairs
|
:return: dictionary containing converted pairs
|
||||||
"""
|
"""
|
||||||
|
@ -168,29 +171,32 @@ def enigma(
|
||||||
plugb: str = "",
|
plugb: str = "",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""
|
"""
|
||||||
The only difference with real-world enigma is that I allowed string input.
|
The only difference with real-world enigma is that ``I`` allowed string input.
|
||||||
All characters are converted to uppercase. (non-letter symbol are ignored)
|
All characters are converted to uppercase. (non-letter symbol are ignored)
|
||||||
How it works:
|
|
||||||
(for every letter in the message)
|
| How it works:
|
||||||
|
| (for every letter in the message)
|
||||||
|
|
||||||
- Input letter goes into the plugboard.
|
- Input letter goes into the plugboard.
|
||||||
If it is connected to another one, switch it.
|
If it is connected to another one, switch it.
|
||||||
|
|
||||||
- Letter goes through 3 rotors.
|
- Letter goes through ``3`` rotors.
|
||||||
Each rotor can be represented as 2 sets of symbol, where one is shuffled.
|
Each rotor can be represented as ``2`` sets of symbol, where one is shuffled.
|
||||||
Each symbol from the first set has corresponding symbol in
|
Each symbol from the first set has corresponding symbol in
|
||||||
the second set and vice versa.
|
the second set and vice versa.
|
||||||
|
|
||||||
example:
|
example::
|
||||||
|
|
||||||
| ABCDEFGHIJKLMNOPQRSTUVWXYZ | e.g. F=D and D=F
|
| ABCDEFGHIJKLMNOPQRSTUVWXYZ | e.g. F=D and D=F
|
||||||
| VKLEPDBGRNWTFCJOHQAMUZYIXS |
|
| VKLEPDBGRNWTFCJOHQAMUZYIXS |
|
||||||
|
|
||||||
- Symbol then goes through reflector (static rotor).
|
- Symbol then goes through reflector (static rotor).
|
||||||
There it is switched with paired symbol
|
There it is switched with paired symbol.
|
||||||
The reflector can be represented as2 sets, each with half of the alphanet.
|
The reflector can be represented as ``2`` sets, each with half of the alphanet.
|
||||||
There are usually 10 pairs of letters.
|
There are usually ``10`` pairs of letters.
|
||||||
|
|
||||||
|
Example::
|
||||||
|
|
||||||
Example:
|
|
||||||
| ABCDEFGHIJKLM | e.g. E is paired to X
|
| ABCDEFGHIJKLM | e.g. E is paired to X
|
||||||
| ZYXWVUTSRQPON | so when E goes in X goes out and vice versa
|
| ZYXWVUTSRQPON | so when E goes in X goes out and vice versa
|
||||||
|
|
||||||
|
@ -211,9 +217,9 @@ def enigma(
|
||||||
|
|
||||||
|
|
||||||
:param text: input message
|
:param text: input message
|
||||||
:param rotor_position: tuple with 3 values in range 1..26
|
:param rotor_position: tuple with ``3`` values in range ``1``.. ``26``
|
||||||
:param rotor_selection: tuple with 3 rotors ()
|
:param rotor_selection: tuple with ``3`` rotors
|
||||||
:param plugb: string containing plugboard configuration (default '')
|
:param plugb: string containing plugboard configuration (default ``''``)
|
||||||
:return: en/decrypted string
|
:return: en/decrypted string
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,10 @@ An RSA prime factor algorithm.
|
||||||
|
|
||||||
The program can efficiently factor RSA prime number given the private key d and
|
The program can efficiently factor RSA prime number given the private key d and
|
||||||
public key e.
|
public key e.
|
||||||
Source: on page 3 of https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf
|
|
||||||
More readable source: https://www.di-mgt.com.au/rsa_factorize_n.html
|
| Source: on page ``3`` of https://crypto.stanford.edu/~dabo/papers/RSA-survey.pdf
|
||||||
|
| More readable source: https://www.di-mgt.com.au/rsa_factorize_n.html
|
||||||
|
|
||||||
large number can take minutes to factor, therefore are not included in doctest.
|
large number can take minutes to factor, therefore are not included in doctest.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -17,6 +19,7 @@ import random
|
||||||
def rsafactor(d: int, e: int, n: int) -> list[int]:
|
def rsafactor(d: int, e: int, n: int) -> list[int]:
|
||||||
"""
|
"""
|
||||||
This function returns the factors of N, where p*q=N
|
This function returns the factors of N, where p*q=N
|
||||||
|
|
||||||
Return: [p, q]
|
Return: [p, q]
|
||||||
|
|
||||||
We call N the RSA modulus, e the encryption exponent, and d the decryption exponent.
|
We call N the RSA modulus, e the encryption exponent, and d the decryption exponent.
|
||||||
|
|
|
@ -2,8 +2,10 @@ def remove_duplicates(key: str) -> str:
|
||||||
"""
|
"""
|
||||||
Removes duplicate alphabetic characters in a keyword (letter is ignored after its
|
Removes duplicate alphabetic characters in a keyword (letter is ignored after its
|
||||||
first appearance).
|
first appearance).
|
||||||
|
|
||||||
:param key: Keyword to use
|
:param key: Keyword to use
|
||||||
:return: String with duplicates removed
|
:return: String with duplicates removed
|
||||||
|
|
||||||
>>> remove_duplicates('Hello World!!')
|
>>> remove_duplicates('Hello World!!')
|
||||||
'Helo Wrd'
|
'Helo Wrd'
|
||||||
"""
|
"""
|
||||||
|
@ -18,6 +20,7 @@ def remove_duplicates(key: str) -> str:
|
||||||
def create_cipher_map(key: str) -> dict[str, str]:
|
def create_cipher_map(key: str) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Returns a cipher map given a keyword.
|
Returns a cipher map given a keyword.
|
||||||
|
|
||||||
:param key: keyword to use
|
:param key: keyword to use
|
||||||
:return: dictionary cipher map
|
:return: dictionary cipher map
|
||||||
"""
|
"""
|
||||||
|
@ -43,9 +46,11 @@ def create_cipher_map(key: str) -> dict[str, str]:
|
||||||
def encipher(message: str, cipher_map: dict[str, str]) -> str:
|
def encipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||||
"""
|
"""
|
||||||
Enciphers a message given a cipher map.
|
Enciphers a message given a cipher map.
|
||||||
|
|
||||||
:param message: Message to encipher
|
:param message: Message to encipher
|
||||||
:param cipher_map: Cipher map
|
:param cipher_map: Cipher map
|
||||||
:return: enciphered string
|
:return: enciphered string
|
||||||
|
|
||||||
>>> encipher('Hello World!!', create_cipher_map('Goodbye!!'))
|
>>> encipher('Hello World!!', create_cipher_map('Goodbye!!'))
|
||||||
'CYJJM VMQJB!!'
|
'CYJJM VMQJB!!'
|
||||||
"""
|
"""
|
||||||
|
@ -55,9 +60,11 @@ def encipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||||
def decipher(message: str, cipher_map: dict[str, str]) -> str:
|
def decipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||||
"""
|
"""
|
||||||
Deciphers a message given a cipher map
|
Deciphers a message given a cipher map
|
||||||
|
|
||||||
:param message: Message to decipher
|
:param message: Message to decipher
|
||||||
:param cipher_map: Dictionary mapping to use
|
:param cipher_map: Dictionary mapping to use
|
||||||
:return: Deciphered string
|
:return: Deciphered string
|
||||||
|
|
||||||
>>> cipher_map = create_cipher_map('Goodbye!!')
|
>>> cipher_map = create_cipher_map('Goodbye!!')
|
||||||
>>> decipher(encipher('Hello World!!', cipher_map), cipher_map)
|
>>> decipher(encipher('Hello World!!', cipher_map), cipher_map)
|
||||||
'HELLO WORLD!!'
|
'HELLO WORLD!!'
|
||||||
|
@ -70,6 +77,7 @@ def decipher(message: str, cipher_map: dict[str, str]) -> str:
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""
|
"""
|
||||||
Handles I/O
|
Handles I/O
|
||||||
|
|
||||||
:return: void
|
:return: void
|
||||||
"""
|
"""
|
||||||
message = input("Enter message to encode or decode: ").strip()
|
message = input("Enter message to encode or decode: ").strip()
|
||||||
|
|
|
@ -22,7 +22,7 @@ TEST_NUMBER_TO_CHARACTER = {val: key for key, val in TEST_CHARACTER_TO_NUMBER.it
|
||||||
|
|
||||||
def __encrypt_part(message_part: str, character_to_number: dict[str, str]) -> str:
|
def __encrypt_part(message_part: str, character_to_number: dict[str, str]) -> str:
|
||||||
"""
|
"""
|
||||||
Arrange the triagram value of each letter of 'message_part' vertically and join
|
Arrange the triagram value of each letter of `message_part` vertically and join
|
||||||
them horizontally.
|
them horizontally.
|
||||||
|
|
||||||
>>> __encrypt_part('ASK', TEST_CHARACTER_TO_NUMBER)
|
>>> __encrypt_part('ASK', TEST_CHARACTER_TO_NUMBER)
|
||||||
|
@ -65,8 +65,8 @@ def __prepare(
|
||||||
"""
|
"""
|
||||||
A helper function that generates the triagrams and assigns each letter of the
|
A helper function that generates the triagrams and assigns each letter of the
|
||||||
alphabet to its corresponding triagram and stores this in a dictionary
|
alphabet to its corresponding triagram and stores this in a dictionary
|
||||||
("character_to_number" and "number_to_character") after confirming if the
|
(`character_to_number` and `number_to_character`) after confirming if the
|
||||||
alphabet's length is 27.
|
alphabet's length is ``27``.
|
||||||
|
|
||||||
>>> test = __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVwxYZ+')
|
>>> test = __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVwxYZ+')
|
||||||
>>> expected = ('IAMABOY','ABCDEFGHIJKLMNOPQRSTUVWXYZ+',
|
>>> expected = ('IAMABOY','ABCDEFGHIJKLMNOPQRSTUVWXYZ+',
|
||||||
|
@ -75,24 +75,28 @@ def __prepare(
|
||||||
True
|
True
|
||||||
|
|
||||||
Testing with incomplete alphabet
|
Testing with incomplete alphabet
|
||||||
|
|
||||||
>>> __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVw')
|
>>> __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVw')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
KeyError: 'Length of alphabet has to be 27.'
|
KeyError: 'Length of alphabet has to be 27.'
|
||||||
|
|
||||||
Testing with extra long alphabets
|
Testing with extra long alphabets
|
||||||
|
|
||||||
>>> __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVwxyzzwwtyyujjgfd')
|
>>> __prepare('I aM a BOy','abCdeFghijkLmnopqrStuVwxyzzwwtyyujjgfd')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
KeyError: 'Length of alphabet has to be 27.'
|
KeyError: 'Length of alphabet has to be 27.'
|
||||||
|
|
||||||
Testing with punctuations that are not in the given alphabet
|
Testing with punctuations that are not in the given alphabet
|
||||||
|
|
||||||
>>> __prepare('am i a boy?','abCdeFghijkLmnopqrStuVwxYZ+')
|
>>> __prepare('am i a boy?','abCdeFghijkLmnopqrStuVwxYZ+')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
ValueError: Each message character has to be included in alphabet!
|
ValueError: Each message character has to be included in alphabet!
|
||||||
|
|
||||||
Testing with numbers
|
Testing with numbers
|
||||||
|
|
||||||
>>> __prepare(500,'abCdeFghijkLmnopqrStuVwxYZ+')
|
>>> __prepare(500,'abCdeFghijkLmnopqrStuVwxYZ+')
|
||||||
Traceback (most recent call last):
|
Traceback (most recent call last):
|
||||||
...
|
...
|
||||||
|
@ -130,9 +134,9 @@ def encrypt_message(
|
||||||
PARAMETERS
|
PARAMETERS
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* message: The message you want to encrypt.
|
* `message`: The message you want to encrypt.
|
||||||
* alphabet (optional): The characters to be used for the cipher .
|
* `alphabet` (optional): The characters to be used for the cipher .
|
||||||
* period (optional): The number of characters you want in a group whilst
|
* `period` (optional): The number of characters you want in a group whilst
|
||||||
encrypting.
|
encrypting.
|
||||||
|
|
||||||
>>> encrypt_message('I am a boy')
|
>>> encrypt_message('I am a boy')
|
||||||
|
@ -169,20 +173,21 @@ def decrypt_message(
|
||||||
decrypt_message
|
decrypt_message
|
||||||
===============
|
===============
|
||||||
|
|
||||||
Decrypts a trifid_cipher encrypted message .
|
Decrypts a trifid_cipher encrypted message.
|
||||||
|
|
||||||
PARAMETERS
|
PARAMETERS
|
||||||
----------
|
----------
|
||||||
|
|
||||||
* message: The message you want to decrypt .
|
* `message`: The message you want to decrypt.
|
||||||
* alphabet (optional): The characters used for the cipher.
|
* `alphabet` (optional): The characters used for the cipher.
|
||||||
* period (optional): The number of characters used in grouping when it
|
* `period` (optional): The number of characters used in grouping when it
|
||||||
was encrypted.
|
was encrypted.
|
||||||
|
|
||||||
>>> decrypt_message('BCDGBQY')
|
>>> decrypt_message('BCDGBQY')
|
||||||
'IAMABOY'
|
'IAMABOY'
|
||||||
|
|
||||||
Decrypting with your own alphabet and period
|
Decrypting with your own alphabet and period
|
||||||
|
|
||||||
>>> decrypt_message('FMJFVOISSUFTFPUFEQQC','FELIXMARDSTBCGHJKNOPQUVWYZ+',5)
|
>>> decrypt_message('FMJFVOISSUFTFPUFEQQC','FELIXMARDSTBCGHJKNOPQUVWYZ+',5)
|
||||||
'AIDETOILECIELTAIDERA'
|
'AIDETOILECIELTAIDERA'
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user