Coverage for kryptic_cypher/cypher/vigenre.py: 98%
44 statements
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-20 18:52 +0000
« prev ^ index » next coverage.py v7.14.2, created at 2026-06-20 18:52 +0000
1import string
3from kryptic_cypher.cypher.base import CypherResult, CypherWithKey, ValidationResult
4from .ceasar import LOWER_ALPHABET, create_alpahbet, create_reverse_alphabet
7class Direction:
8 ENCODE = "encode"
9 DECODE = "decode"
12def key_to_alphabets(key: str, direction: Direction) -> list[dict[str, str]]:
13 alpha_method = (
14 create_alpahbet if direction == Direction.ENCODE else create_reverse_alphabet
15 )
16 all_alphabets = []
18 for letter in key.lower():
20 shift_value = LOWER_ALPHABET.index(letter)
21 if shift_value < 0:
22 raise ValueError("Somehow got a letter that isn't in the alphabet.")
24 all_alphabets.append(alpha_method(shift_value))
25 return all_alphabets
28class VigenreCypher(CypherWithKey):
29 """
30 The Vigen\u00e9re Cypher is a polyalphabetic cypher based on the use of mulitple Caesar Cyphers to encrypt.
32 First you choose the message you wish to encrypt and then a key word or phrase if you want
33 text: This is something important
34 key: sure
36 then you place the key under the text to start the encryption
37 encrypt: This is something important
38 sure su resuresur suresures
40 we use the ordinal value of the key for example and shift each letter by that amount to encrypt the phrase.
41 t h i s
42 s u r e
43 18 20 17 4
45 so then t would be l, h would be b, i would be z, and s would be w and so forth for a fully encoded phrase of
46 Encrypted: lbzw am jseyklahx mejfvluex
48 """
50 @classmethod
51 def validate_key(cls, key: str):
52 if not key:
53 return ValidationResult.fail("Key cannot be empty.")
54 keys = key.split(" ")
55 if len(keys) > 1:
56 return ValidationResult.fail("Key must be a single word.")
57 if any(c not in string.ascii_letters for c in key):
58 return ValidationResult.fail("Key must be only letters.")
60 return ValidationResult.ok()
62 def encode(self, text: str, key: str) -> CypherResult:
63 alphabits = key_to_alphabets(key, Direction.ENCODE)
64 encoded_text = ""
65 alphbits_index = 0
66 for letter in text:
67 alphabet = alphabits[alphbits_index % len(alphabits)]
68 encoded_text += alphabet.get(letter, letter)
69 alphbits_index += 1
70 return CypherResult.ok(text, encoded_text)
72 def decode(self, text: str, key: str) -> CypherResult:
73 alphabits = key_to_alphabets(key, Direction.DECODE)
74 decoded_text = ""
75 alphbits_index = 0
76 for letter in text:
77 alphabet = alphabits[alphbits_index % len(alphabits)]
78 decoded_text += alphabet.get(letter, letter)
79 alphbits_index += 1
80 return CypherResult.ok(text, decoded_text)