diff --git a/homework00/hello.py b/homework00/hello.py index efe8767..5802c29 100644 --- a/homework00/hello.py +++ b/homework00/hello.py @@ -1,5 +1,5 @@ def get_greeting(name: str) -> str: - pass + return f"Hello, {name}!" if __name__ == "__main__": diff --git a/homework01/caesar.py b/homework01/caesar.py index 09c3681..7b05368 100644 --- a/homework01/caesar.py +++ b/homework01/caesar.py @@ -1,46 +1,28 @@ import typing as tp +from string import ascii_lowercase as lower +from string import ascii_uppercase as upper def encrypt_caesar(plaintext: str, shift: int = 3) -> str: - """ - Encrypts plaintext using a Caesar cipher. - - >>> encrypt_caesar("PYTHON") - 'SBWKRQ' - >>> encrypt_caesar("python") - 'sbwkrq' - >>> encrypt_caesar("Python3.6") - 'Sbwkrq3.6' - >>> encrypt_caesar("") - '' - """ ciphertext = "" - # PUT YOUR CODE HERE + for char in plaintext: + if char.isalpha(): + if char.islower(): + char = lower[(lower.index(char) + shift) % 26] + else: + char = upper[(upper.index(char) + shift) % 26] + ciphertext += char return ciphertext def decrypt_caesar(ciphertext: str, shift: int = 3) -> str: - """ - Decrypts a ciphertext using a Caesar cipher. - - >>> decrypt_caesar("SBWKRQ") - 'PYTHON' - >>> decrypt_caesar("sbwkrq") - 'python' - >>> decrypt_caesar("Sbwkrq3.6") - 'Python3.6' - >>> decrypt_caesar("") - '' - """ - plaintext = "" - # PUT YOUR CODE HERE - return plaintext + return encrypt_caesar(ciphertext, -shift) def caesar_breaker_brute_force(ciphertext: str, dictionary: tp.Set[str]) -> int: - """ - Brute force breaking a Caesar cipher. - """ best_shift = 0 - # PUT YOUR CODE HERE + for shift in range(26): + decrypted_msg = decrypt_caesar(ciphertext, shift) + if decrypted_msg in dictionary: + best_shift = shift return best_shift diff --git a/homework01/rsa.py b/homework01/rsa.py index b777be5..1d56554 100644 --- a/homework01/rsa.py +++ b/homework01/rsa.py @@ -3,43 +3,32 @@ 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 - """ - # PUT YOUR CODE HERE - pass + for div in range(2, int(n**0.5) + 1): + if n % div == 0: + return False + return n != 1 def gcd(a: int, b: int) -> int: - """ - Euclid's algorithm for determining the greatest common divisor. + if b == 0: + return a + return gcd(b, a % b) - >>> gcd(12, 15) - 3 - >>> gcd(3, 7) - 1 - """ - # PUT YOUR CODE HERE - pass +def gcdex(a, b): + if b == 0: + return a, 1, 0 + else: + d, x, y = gcdex(b, a % b) + return d, y, x - y * (a // b) -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 - """ - # PUT YOUR CODE HERE - pass +def multiplicative_inverse(a: int, n: int) -> int: + d, x, y = gcdex(a, n) + if d == 1: + return (x % n + n) % n + else: + return 0 def generate_keypair(p: int, q: int) -> tp.Tuple[tp.Tuple[int, int], tp.Tuple[int, int]]: @@ -49,10 +38,10 @@ 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 = pq - # PUT YOUR CODE HERE + n = p * q # 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) @@ -85,7 +74,7 @@ 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] + plain = [chr((char**key) % n) for char in ciphertext] # Return the array of bytes as a string return "".join(plain) diff --git a/homework01/vigenere.py b/homework01/vigenere.py index e51742e..1cbb09d 100644 --- a/homework01/vigenere.py +++ b/homework01/vigenere.py @@ -1,30 +1,18 @@ -def encrypt_vigenere(plaintext: str, keyword: str) -> str: - """ - Encrypts plaintext using a Vigenere cipher. +from caesar import decrypt_caesar, encrypt_caesar - >>> encrypt_vigenere("PYTHON", "A") - 'PYTHON' - >>> encrypt_vigenere("python", "a") - 'python' - >>> encrypt_vigenere("ATTACKATDAWN", "LEMON") - 'LXFOPVEFRNHR' - """ - ciphertext = "" - # PUT YOUR CODE HERE - return ciphertext +def encrypt_vigenere(plaintext: str, keyword: str, encode: bool = True) -> str: + ciphertext = [] + for index, char in enumerate(plaintext.lower()): + shift = ord(keyword[index % len(keyword)].lower()) - 97 + if encode: + ciphertext.append(encrypt_caesar(char, shift)) + else: + ciphertext.append(decrypt_caesar(char, shift)) + if plaintext[index].isupper(): + ciphertext[-1] = ciphertext[-1].upper() + return "".join(ciphertext) -def decrypt_vigenere(ciphertext: str, keyword: str) -> str: - """ - Decrypts a ciphertext using a Vigenere cipher. - >>> decrypt_vigenere("PYTHON", "A") - 'PYTHON' - >>> decrypt_vigenere("python", "a") - 'python' - >>> decrypt_vigenere("LXFOPVEFRNHR", "LEMON") - 'ATTACKATDAWN' - """ - plaintext = "" - # PUT YOUR CODE HERE - return plaintext +def decrypt_vigenere(ciphertext: str, keyword: str) -> str: + return encrypt_vigenere(ciphertext, keyword, encode=False)