diff --git a/ciphers/porta_cipher.py b/ciphers/porta_cipher.py new file mode 100644 index 000000000..a8e794159 --- /dev/null +++ b/ciphers/porta_cipher.py @@ -0,0 +1,110 @@ +alphabet = { + "A": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"), + "B": ("ABCDEFGHIJKLM", "NOPQRSTUVWXYZ"), + "C": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"), + "D": ("ABCDEFGHIJKLM", "ZNOPQRSTUVWXY"), + "E": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"), + "F": ("ABCDEFGHIJKLM", "YZNOPQRSTUVWX"), + "G": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"), + "H": ("ABCDEFGHIJKLM", "XYZNOPQRSTUVW"), + "I": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"), + "J": ("ABCDEFGHIJKLM", "WXYZNOPQRSTUV"), + "K": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"), + "L": ("ABCDEFGHIJKLM", "VWXYZNOPQRSTU"), + "M": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"), + "N": ("ABCDEFGHIJKLM", "UVWXYZNOPQRST"), + "O": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"), + "P": ("ABCDEFGHIJKLM", "TUVWXYZNOPQRS"), + "Q": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"), + "R": ("ABCDEFGHIJKLM", "STUVWXYZNOPQR"), + "S": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"), + "T": ("ABCDEFGHIJKLM", "RSTUVWXYZNOPQ"), + "U": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"), + "V": ("ABCDEFGHIJKLM", "QRSTUVWXYZNOP"), + "W": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"), + "X": ("ABCDEFGHIJKLM", "PQRSTUVWXYZNO"), + "Y": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"), + "Z": ("ABCDEFGHIJKLM", "OPQRSTUVWXYZN"), +} + + +def generate_table(key): + """ + >>> generate_table('marvin') # doctest: +NORMALIZE_WHITESPACE + [('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), + ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'), + ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')] + """ + return [alphabet[char] for char in key.upper()] + + +def encrypt(key, words): + """ + >>> encrypt('marvin', 'jessica') + 'QRACRWU' + """ + cipher = "" + count = 0 + table = generate_table(key) + for char in words.upper(): + cipher += get_opponent(table[count], char) + count = (count + 1) % len(table) + return cipher + + +def decrypt(key, words): + """ + >>> decrypt('marvin', 'QRACRWU') + 'JESSICA' + """ + return encrypt(key, words) + + +def get_position(table, char): + """ + >>> table = [ + ... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), + ... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'), + ... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')] + >>> get_position(table, 'A') + (None, None) + """ + if char in table[0]: + row = 0 + else: + row = 1 if char in table[1] else -1 + return (None, None) if row == -1 else (row, table[row].index(char)) + + +def get_opponent(table, char): + """ + >>> table = [ + ... ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST'), ('ABCDEFGHIJKLM', 'NOPQRSTUVWXYZ'), + ... ('ABCDEFGHIJKLM', 'STUVWXYZNOPQR'), ('ABCDEFGHIJKLM', 'QRSTUVWXYZNOP'), + ... ('ABCDEFGHIJKLM', 'WXYZNOPQRSTUV'), ('ABCDEFGHIJKLM', 'UVWXYZNOPQRST')] + >>> get_opponent(table, 'A') + 'A' + """ + row, col = get_position(table, char.upper()) + if row == 1: + return table[0][col] + else: + return table[1][col] if row == 0 else char + + +if __name__ == "__main__": + import doctest + + doctest.testmod() # Fist ensure that all our tests are passing... + """ + ENTER KEY: marvin + ENTER TEXT TO ENCRYPT: jessica + ENCRYPTED: QRACRWU + DECRYPTED WITH KEY: JESSICA + """ + key = input("ENTER KEY: ").strip() + text = input("ENTER TEXT TO ENCRYPT: ").strip() + cipher_text = encrypt(key, text) + + print(f"ENCRYPTED: {cipher_text}") + print(f"DECRYPTED WITH KEY: {decrypt(key, cipher_text)}")