From e5f35aa0f8e7937e391336b397fe59df10574881 Mon Sep 17 00:00:00 2001 From: Marzhal Date: Sun, 24 Nov 2024 00:35:33 +0100 Subject: [PATCH 1/4] cipher: add scytale cipher --- ciphers/scytale_cipher.py | 57 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 ciphers/scytale_cipher.py diff --git a/ciphers/scytale_cipher.py b/ciphers/scytale_cipher.py new file mode 100644 index 000000000000..2c3f617bc88d --- /dev/null +++ b/ciphers/scytale_cipher.py @@ -0,0 +1,57 @@ +def encrypt_scytale_cipher(message: str, key: int) -> str: + """ + Encrypts a message using the Scytale Cipher. + + :param message: Text to encrypt. + :param key: Number of rows (key). + :return: Encrypted message. + """ + message = message.replace(" ", "") # Optional: remove spaces + ciphertext = [''] * key + + # Distribute characters across rows based on the key + for i in range(len(message)): + ciphertext[i % key] += message[i] + + return ''.join(ciphertext) + + +def decrypt_scytale_cipher(ciphertext: str, key: int) -> str: + """ + Decrypts a message encrypted with the Scytale Cipher. + + :param ciphertext: Encrypted text. + :param key: Number of rows (key). + :return: Decrypted message. + """ + num_cols = -(-len(ciphertext) // key) # Calculate number of columns (round up) + num_rows = key + num_shaded_boxes = (num_cols * num_rows) - len(ciphertext) # Extra unused boxes + + plaintext = [''] * num_cols + col = 0 + row = 0 + + # Rebuild the plaintext row by row + for char in ciphertext: + plaintext[col] += char + col += 1 + # Reset column and move to next row if end of column is reached + if (col == num_cols) or (col == num_cols - 1 and row >= num_rows - num_shaded_boxes): + col = 0 + row += 1 + + return ''.join(plaintext) + + +# Example usage +message = "HELLO WORLD FROM SCYTALE" +key = 5 + +# Encrypt the message +ciphered = encrypt_scytale_cipher(message, key) +print("Encrypted:", ciphered) + +# Decrypt the message +deciphered = decrypt_scytale_cipher(ciphered, key) +print("Decrypted:", deciphered) From 575ba8bf1a1d1d49fe928f5a89b70a4141cd3983 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 23:38:58 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ciphers/scytale_cipher.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ciphers/scytale_cipher.py b/ciphers/scytale_cipher.py index 2c3f617bc88d..a63dee3228ab 100644 --- a/ciphers/scytale_cipher.py +++ b/ciphers/scytale_cipher.py @@ -1,25 +1,25 @@ def encrypt_scytale_cipher(message: str, key: int) -> str: """ Encrypts a message using the Scytale Cipher. - + :param message: Text to encrypt. :param key: Number of rows (key). :return: Encrypted message. """ message = message.replace(" ", "") # Optional: remove spaces - ciphertext = [''] * key + ciphertext = [""] * key # Distribute characters across rows based on the key for i in range(len(message)): ciphertext[i % key] += message[i] - return ''.join(ciphertext) + return "".join(ciphertext) def decrypt_scytale_cipher(ciphertext: str, key: int) -> str: """ Decrypts a message encrypted with the Scytale Cipher. - + :param ciphertext: Encrypted text. :param key: Number of rows (key). :return: Decrypted message. @@ -28,7 +28,7 @@ def decrypt_scytale_cipher(ciphertext: str, key: int) -> str: num_rows = key num_shaded_boxes = (num_cols * num_rows) - len(ciphertext) # Extra unused boxes - plaintext = [''] * num_cols + plaintext = [""] * num_cols col = 0 row = 0 @@ -37,11 +37,13 @@ def decrypt_scytale_cipher(ciphertext: str, key: int) -> str: plaintext[col] += char col += 1 # Reset column and move to next row if end of column is reached - if (col == num_cols) or (col == num_cols - 1 and row >= num_rows - num_shaded_boxes): + if (col == num_cols) or ( + col == num_cols - 1 and row >= num_rows - num_shaded_boxes + ): col = 0 row += 1 - return ''.join(plaintext) + return "".join(plaintext) # Example usage From 29a6da05ff1c83b111a49d2a2b808eef215dbe6e Mon Sep 17 00:00:00 2001 From: Marzhal Date: Sun, 24 Nov 2024 00:44:04 +0100 Subject: [PATCH 3/4] cipher: add columnar transposition cipher --- ciphers/columnar_transposition_cipher.py | 73 ++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 ciphers/columnar_transposition_cipher.py diff --git a/ciphers/columnar_transposition_cipher.py b/ciphers/columnar_transposition_cipher.py new file mode 100644 index 000000000000..f230d4e16ab3 --- /dev/null +++ b/ciphers/columnar_transposition_cipher.py @@ -0,0 +1,73 @@ +import math + +def encrypt_columnar_cipher(message: str, key: str) -> str: + """ + Encrypts a message using the Columnar Transposition Cipher. + + :param message: Text to encrypt. + :param key: String key used to define column order. + :return: Encrypted message. + """ + # Remove spaces and calculate dimensions + message = message.replace(" ", "") + num_cols = len(key) + num_rows = math.ceil(len(message) / num_cols) + + # Fill the grid with characters + grid = [''] * num_cols + for i, char in enumerate(message): + grid[i % num_cols] += char + + # Sort columns based on the key order + sorted_key_indices = sorted(range(len(key)), key=lambda k: key[k]) + ciphertext = ''.join([grid[i] for i in sorted_key_indices]) + + return ciphertext + + +def decrypt_columnar_cipher(ciphertext: str, key: str) -> str: + """ + Decrypts a message encrypted with the Columnar Transposition Cipher. + + :param ciphertext: Encrypted text. + :param key: String key used to define column order. + :return: Decrypted message. + """ + num_cols = len(key) + num_rows = math.ceil(len(ciphertext) / num_cols) + num_shaded_boxes = (num_cols * num_rows) - len(ciphertext) + + # Sort columns based on the key order + sorted_key_indices = sorted(range(len(key)), key=lambda k: key[k]) + col_lengths = [num_rows] * num_cols + for i in range(num_shaded_boxes): + col_lengths[sorted_key_indices[-(i+1)]] -= 1 + + # Distribute ciphertext into columns based on the sorted key + grid = [] + start = 0 + for col_length in col_lengths: + grid.append(ciphertext[start:start + col_length]) + start += col_length + + # Rebuild plaintext row by row + plaintext = '' + for i in range(num_rows): + for j in range(num_cols): + if i < len(grid[sorted_key_indices[j]]): + plaintext += grid[sorted_key_indices[j]][i] + + return plaintext + + +# Example usage +message = "HELLO WORLD FROM COLUMNAR" +key = "3412" + +# Encrypt the message +encrypted = encrypt_columnar_cipher(message, key) +print("Encrypted:", encrypted) + +# Decrypt the message +decrypted = decrypt_columnar_cipher(encrypted, key) +print("Decrypted:", decrypted) From a23b0f5177dd4193e12283745a01893f3eb5fdd2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 23 Nov 2024 23:44:43 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- ciphers/columnar_transposition_cipher.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ciphers/columnar_transposition_cipher.py b/ciphers/columnar_transposition_cipher.py index f230d4e16ab3..a9857ed87f4f 100644 --- a/ciphers/columnar_transposition_cipher.py +++ b/ciphers/columnar_transposition_cipher.py @@ -1,9 +1,10 @@ import math + def encrypt_columnar_cipher(message: str, key: str) -> str: """ Encrypts a message using the Columnar Transposition Cipher. - + :param message: Text to encrypt. :param key: String key used to define column order. :return: Encrypted message. @@ -12,15 +13,15 @@ def encrypt_columnar_cipher(message: str, key: str) -> str: message = message.replace(" ", "") num_cols = len(key) num_rows = math.ceil(len(message) / num_cols) - + # Fill the grid with characters - grid = [''] * num_cols + grid = [""] * num_cols for i, char in enumerate(message): grid[i % num_cols] += char # Sort columns based on the key order sorted_key_indices = sorted(range(len(key)), key=lambda k: key[k]) - ciphertext = ''.join([grid[i] for i in sorted_key_indices]) + ciphertext = "".join([grid[i] for i in sorted_key_indices]) return ciphertext @@ -28,7 +29,7 @@ def encrypt_columnar_cipher(message: str, key: str) -> str: def decrypt_columnar_cipher(ciphertext: str, key: str) -> str: """ Decrypts a message encrypted with the Columnar Transposition Cipher. - + :param ciphertext: Encrypted text. :param key: String key used to define column order. :return: Decrypted message. @@ -41,17 +42,17 @@ def decrypt_columnar_cipher(ciphertext: str, key: str) -> str: sorted_key_indices = sorted(range(len(key)), key=lambda k: key[k]) col_lengths = [num_rows] * num_cols for i in range(num_shaded_boxes): - col_lengths[sorted_key_indices[-(i+1)]] -= 1 + col_lengths[sorted_key_indices[-(i + 1)]] -= 1 # Distribute ciphertext into columns based on the sorted key grid = [] start = 0 for col_length in col_lengths: - grid.append(ciphertext[start:start + col_length]) + grid.append(ciphertext[start : start + col_length]) start += col_length # Rebuild plaintext row by row - plaintext = '' + plaintext = "" for i in range(num_rows): for j in range(num_cols): if i < len(grid[sorted_key_indices[j]]):