diff --git a/homework01/caesar.py b/homework01/caesar.py index 3d77953..bd7cc6c 100644 --- a/homework01/caesar.py +++ b/homework01/caesar.py @@ -1,5 +1,6 @@ import typing as tp + def encrypt_caesar(plaintext: str, shift: int = 3) -> str: """ Encrypts plaintext using a Caesar cipher. @@ -14,24 +15,17 @@ def encrypt_caesar(plaintext: str, shift: int = 3) -> str: '' """ ciphertext = "" - for i in plaintext: - if 65 <= ord(i) <= 122: + if i.isalpha(): if i.isupper(): - if ord(i) >= 87: - ciphertext += chr(65 + (ord(i) + shift) % 91) - else: - ciphertext += chr(ord(i) + shift) + ciphertext += chr(((ord(i) - ord("A")) + shift) % 26 + ord("A")) else: - if ord(i) >= 119: - ciphertext += chr(97 + (ord(i) + shift) % 123) - else: - ciphertext += chr(ord(i) + shift) + ciphertext += chr(((ord(i) - ord("a")) + shift) % 26 + ord("a")) else: ciphertext += i - return ciphertext + def decrypt_caesar(ciphertext: str, shift: int = 3) -> str: """ Decrypts a ciphertext using a Caesar cipher. @@ -46,22 +40,14 @@ def decrypt_caesar(ciphertext: str, shift: int = 3) -> str: '' """ plaintext = "" - for i in ciphertext: - if 65 <= ord(i) <= 122: + if i.isalpha(): if i.isupper(): - if ord(i) <= 68: - plaintext += chr(90 - (2 - (ord(i) % 65))) - else: - plaintext += chr(ord(i) - shift) + plaintext += chr(((ord(i) - ord("A")) - shift) % 26 + ord("A")) else: - if ord(i) <= 99: - plaintext += chr(122 - (2 - (ord(i) % 97))) - else: - plaintext += chr(ord(i) - shift) + plaintext += chr(((ord(i) - ord("a")) - shift) % 26 + ord("a")) else: plaintext += i - return plaintext diff --git a/homework01/rsa.py b/homework01/rsa.py index a3578ab..2903f2b 100644 --- a/homework01/rsa.py +++ b/homework01/rsa.py @@ -1,36 +1,19 @@ import random import typing as tp + def is_prime(n: int) -> bool: - """ - Tests to see if a number is prime. - - >>> is_prime(2) - True - >>> is_prime(11) - True - >>> is_prime(8) - False - """ - k = 0 - for i in range(2, n): + if n <= 1: + return False + flag = True + for i in range(2, n // 2 + 1): if n % i == 0: - k = 1 - if k > 0: - return False - - return True + flag = False + break + return flag def gcd(a: int, b: int) -> int: - """ - Euclid's algorithm for determining the greatest common divisor. - - >>> gcd(12, 15) - 3 - >>> gcd(3, 7) - 1 - """ while a != 0 and b != 0: if a >= b: a %= b @@ -40,13 +23,6 @@ def gcd(a: int, b: int) -> int: def multiplicative_inverse(e: int, phi: int) -> int: - """ - Euclid's extended algorithm for finding the multiplicative - inverse of two numbers. - - >>> multiplicative_inverse(7, 40) - 23 - """ return pow(e, -1, phi) @@ -57,44 +33,30 @@ def generate_keypair(p: int, q: int) -> tp.Tuple[tp.Tuple[int, int], tp.Tuple[in raise ValueError("p and q cannot be equal") n = p * q - # PUT YOUR CODE HERE - phi = (p-1) * (q-1) - # PUT YOUR CODE HERE + phi = (p - 1) * (q - 1) - # Choose an integer e such that e and phi(n) are coprime e = random.randrange(1, phi) - # Use Euclid's Algorithm to verify that e and phi(n) are coprime g = gcd(e, phi) while g != 1: e = random.randrange(1, phi) g = gcd(e, phi) - # Use Extended Euclid's Algorithm to generate the private key d = multiplicative_inverse(e, phi) - # Return public and private keypair - # Public key is (e, n) and private key is (d, n) return ((e, n), (d, n)) def encrypt(pk: tp.Tuple[int, int], plaintext: str) -> tp.List[int]: - # Unpack the key into it's components key, n = pk - # Convert each letter in the plaintext to numbers based on - # the character using a^b mod m cipher = [(ord(char) ** key) % n for char in plaintext] - # Return the array of bytes return cipher def decrypt(pk: tp.Tuple[int, int], ciphertext: tp.List[int]) -> str: - # Unpack the key into its components key, n = pk - # Generate the plaintext based on the ciphertext and key using a^b mod m - plain = [chr((char ** key) % n) for char in ciphertext] - # Return the array of bytes as a string + plain = [chr((char**key) % n) for char in ciphertext] return "".join(plain) diff --git a/homework01/vigenere.py b/homework01/vigenere.py index 933911b..1f27a2e 100644 --- a/homework01/vigenere.py +++ b/homework01/vigenere.py @@ -10,21 +10,24 @@ def encrypt_vigenere(plaintext: str, keyword: str) -> str: 'LXFOPVEFRNHR' """ ciphertext = "" - - key_length = len(keyword) - key_int = [ord(i) for i in keyword] - plaintext_int = [ord(i) for i in plaintext] - - for i in range(len(plaintext_int)): - if plaintext_int[i] == 32: - plaintext += " " - elif plaintext[i].isupper(): - value = (plaintext_int[i] + key_int[i % key_length]) % 26 - ciphertext += chr(value + 65) + for i in range(len(plaintext)): + if plaintext[i].isalpha(): + if plaintext[i].isupper(): + ciphertext += chr( + (ord(plaintext[i]) - 2 * ord("A") + ord(keyword[i % len(keyword)].upper())) + % 26 + % 26 + + ord("A") + ) + else: + ciphertext += chr( + (ord(plaintext[i]) - 2 * ord("a") + ord(keyword[i % len(keyword)].lower())) + % 26 + % 26 + + ord("a") + ) else: - value = (plaintext_int[i] + key_int[i % key_length] - 64) % 26 - ciphertext += chr(value + 97) - + ciphertext += plaintext[i] return ciphertext @@ -40,18 +43,16 @@ def decrypt_vigenere(ciphertext: str, keyword: str) -> str: 'ATTACKATDAWN' """ plaintext = "" - key_length = len(keyword) - key_int = [ord(i) for i in keyword] - ciphertext_int = [ord(i) for i in ciphertext] - - for i in range(len(ciphertext_int)): - if ciphertext_int[i] == 32: - plaintext += " " - elif chr(ciphertext_int[i]).isupper(): - value = (ciphertext_int[i] - key_int[i % key_length]) % 26 - plaintext += chr(value + 65) + for i in range(len(ciphertext)): + if ciphertext[i].isalpha(): + if ciphertext[i].isupper(): + plaintext += chr( + (ord(ciphertext[i]) - ord(keyword[i % len(keyword)].upper())) % 26 + ord("A") + ) + else: + plaintext += chr( + (ord(ciphertext[i]) - ord(keyword[i % len(keyword)].lower())) % 26 + ord("a") + ) else: - value = (ciphertext_int[i] - key_int[i % key_length]) % 26 - plaintext += chr(value + 97) - + plaintext += ciphertext[i] return plaintext