python program for the fractionated morse cipher the fractionated morse cipher first converts the plaintext to morse code then enciphers fixedsize blocks of morse code back to letters this procedure means plaintext letters are mixed into the ciphertext letters making it more secure than substitution ciphers http practicalcryptography comciphersfractionatedmorsecipher define possible trigrams of morse code create a reverse dictionary for morse code encode a plaintext message into morse code args plaintext the plaintext message to encode returns the morse code representation of the plaintext message example encodetomorsedefend the east x x x x x xxx x xx x x x encrypt a plaintext message using fractionated morse cipher args plaintext the plaintext message to encrypt key the encryption key returns the encrypted ciphertext example encryptfractionatedmorsedefend the east roundtable esoavvljrsstrx ensure morsecode length is a multiple of 3 decrypt a ciphertext message encrypted with fractionated morse cipher args ciphertext the ciphertext message to decrypt key the decryption key returns the decrypted plaintext message example decryptfractionatedmorseesoavvljrsstrx roundtable defend the east example usage of fractionated morse cipher define possible trigrams of morse code create a reverse dictionary for morse code encode a plaintext message into morse code args plaintext the plaintext message to encode returns the morse code representation of the plaintext message example encode_to_morse defend the east x x x x x xx x x xx x x x encrypt a plaintext message using fractionated morse cipher args plaintext the plaintext message to encrypt key the encryption key returns the encrypted ciphertext example encrypt_fractionated_morse defend the east roundtable esoavvljrsstrx ensure morse_code length is a multiple of 3 decrypt a ciphertext message encrypted with fractionated morse cipher args ciphertext the ciphertext message to decrypt key the decryption key returns the decrypted plaintext message example decrypt_fractionated_morse esoavvljrsstrx roundtable defend the east example usage of fractionated morse cipher
import string

MORSE_CODE_DICT = {
    "A": ".-",
    "B": "-...",
    "C": "-.-.",
    "D": "-..",
    "E": ".",
    "F": "..-.",
    "G": "--.",
    "H": "....",
    "I": "..",
    "J": ".---",
    "K": "-.-",
    "L": ".-..",
    "M": "--",
    "N": "-.",
    "O": "---",
    "P": ".--.",
    "Q": "--.-",
    "R": ".-.",
    "S": "...",
    "T": "-",
    "U": "..-",
    "V": "...-",
    "W": ".--",
    "X": "-..-",
    "Y": "-.--",
    "Z": "--..",
    " ": "",
}


MORSE_COMBINATIONS = [
    "...",
    "..-",
    "..x",
    ".-.",
    ".--",
    ".-x",
    ".x.",
    ".x-",
    ".xx",
    "-..",
    "-.-",
    "-.x",
    "--.",
    "---",
    "--x",
    "-x.",
    "-x-",
    "-xx",
    "x..",
    "x.-",
    "x.x",
    "x-.",
    "x--",
    "x-x",
    "xx.",
    "xx-",
    "xxx",
]


REVERSE_DICT = {value: key for key, value in MORSE_CODE_DICT.items()}


def encode_to_morse(plaintext: str) -> str:
    
    return "x".join([MORSE_CODE_DICT.get(letter.upper(), "") for letter in plaintext])


def encrypt_fractionated_morse(plaintext: str, key: str) -> str:
    
    morse_code = encode_to_morse(plaintext)
    key = key.upper() + string.ascii_uppercase
    key = "".join(sorted(set(key), key=key.find))

    
    padding_length = 3 - (len(morse_code) % 3)
    morse_code += "x" * padding_length

    fractionated_morse_dict = {v: k for k, v in zip(key, MORSE_COMBINATIONS)}
    fractionated_morse_dict["xxx"] = ""
    encrypted_text = "".join(
        [
            fractionated_morse_dict[morse_code[i : i + 3]]
            for i in range(0, len(morse_code), 3)
        ]
    )
    return encrypted_text


def decrypt_fractionated_morse(ciphertext: str, key: str) -> str:
    
    key = key.upper() + string.ascii_uppercase
    key = "".join(sorted(set(key), key=key.find))

    inverse_fractionated_morse_dict = dict(zip(key, MORSE_COMBINATIONS))
    morse_code = "".join(
        [inverse_fractionated_morse_dict.get(letter, "") for letter in ciphertext]
    )
    decrypted_text = "".join(
        [REVERSE_DICT[code] for code in morse_code.split("x")]
    ).strip()
    return decrypted_text


if __name__ == "__main__":
    
    plaintext = "defend the east"
    print("Plain Text:", plaintext)
    key = "ROUNDTABLE"

    ciphertext = encrypt_fractionated_morse(plaintext, key)
    print("Encrypted:", ciphertext)

    decrypted_text = decrypt_fractionated_morse(ciphertext, key)
    print("Decrypted:", decrypted_text)