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

1import string 

2 

3from kryptic_cypher.cypher.base import CypherResult, CypherWithKey, ValidationResult 

4from .ceasar import LOWER_ALPHABET, create_alpahbet, create_reverse_alphabet 

5 

6 

7class Direction: 

8 ENCODE = "encode" 

9 DECODE = "decode" 

10 

11 

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 = [] 

17 

18 for letter in key.lower(): 

19 

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.") 

23 

24 all_alphabets.append(alpha_method(shift_value)) 

25 return all_alphabets 

26 

27 

28class VigenreCypher(CypherWithKey): 

29 """ 

30 The Vigen\u00e9re Cypher is a polyalphabetic cypher based on the use of mulitple Caesar Cyphers to encrypt. 

31 

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 

35 

36 then you place the key under the text to start the encryption 

37 encrypt: This is something important 

38 sure su resuresur suresures 

39 

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 

44 

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 

47 

48 """ 

49 

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.") 

59 

60 return ValidationResult.ok() 

61 

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) 

71 

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)