Ciphers
- class blaise.ciphers.Caesar
Bases:
CipherThe Caesar Cipher is the simplest of ciphers, where each letter is shifted by a fixed amount in either direction. Wikipedia page: https://en.wikipedia.org/wiki/Caesar_cipher
- crack(ciphertext, scorer: Scorer | None = None, top_n: int | None = None) DataFrame
Cracks a Caesar shift cipher. It will try all shifts and score them with an ngram scorer.
- Parameters:
ciphertext (str) – The ciphertext to crack.
scorer (optional) – Scorer function to evaluate plaintext candidates.
top_n (optional) – Number of top results to return.
Example
>>> Caesar().crack('EBIILTLOIA', top_n=3) shape: (3, 3) ┌─────┬────────────┬──────────┐ │ key ┆ plaintext ┆ score │ │ --- ┆ --- ┆ --- │ │ i64 ┆ str ┆ f64 │ ╞═════╪════════════╪══════════╡ │ 23 ┆ HELLOWORLD ┆ 1.535752 │ │ 8 ┆ WTAADLDGAS ┆ 1.995915 │ │ 19 ┆ LIPPSASVPH ┆ 2.051054 │ └─────┴────────────┴──────────┘
- decrypt(ciphertext: str, key: int) str
Decrypts a Caesar shift that has been applied. Positive key value indicates that it was encrypted with a right shift, and negative with a left shift.
- encrypt(plaintext: str, key: int) str
Applies a Caesar shift to plaintext. Positive key value is a right shift, negative is a left shift.
- class blaise.ciphers.Playfair(fill_char='X', alt_fill_char='Q', missing_letter: str = 'J->I')
Bases:
CipherWikipedia page: https://en.wikipedia.org/wiki/Playfair_cipher.
- decrypt(ciphertext: str, key: str, remove_fill=False) str
Decrypts using the Playfair cipher. Will fail if: - Any bigram is a repeat - Any character in the ciphertext isn’t present in the alphabet provided
>>> Playfair().decrypt("BMODZBXDNABEKUDMUIXMMOUVIF", "playfairexample") 'HIDETHEGOLDINTHETREXESTUMP'
Optionally there is a heuristic approach to removing fill characters. It isn’t perfect - will be caught out by a legitimate EX EC for example - would remove the X in that case.
>>> Playfair().decrypt("BMODZBXDNABEKUDMUIXMMOUVIF", "playfairexample", remove_fill=True) 'HIDETHEGOLDINTHETREESTUMP'
- encrypt(plaintext: str, key: str) str
Encrypts using the Playfair cipher.
>>> Playfair().encrypt("hide the gold in the tree stump", "playfairexample") 'BMODZBXDNABEKUDMUIXMMOUVIF'
- class blaise.ciphers.Vigenere
Bases:
CipherThe Vigenère Cipher is a straightforward cipher formed by interleaving Caesar shifts. Wikipedia page: https://en.wikipedia.org/wiki/Vigen%C3%A8re_cipher.
- crack(ciphertext: str, key_length: int | Iterable[int] = range(3, 8), top_n=10, n_trials: int = 1000, scorer=None, dist='en_wiki') DataFrame
Cracks a Vigenère cipher.
- Parameters:
ciphertext (str) – The ciphertext to crack. Note that non-alphabetic characters are ignored.
key_length (int | Iterable[int], optional) – The length(s) of the key to try. If an integer is supplied, the function will attempt to crack a key of that exact length. If an iterable is supplied, the function will iterate over each length in the iterable. The default is
range(3, 8), which tries key lengths 3 through 7.top_n (int, optional) – The maximum number of results to return. Results are sorted by the provided
scorer.n_trials (int, optional) – The maximum number of key combinations to evaluate for each
key_length. This limits the search space for long keys.scorer (Scorer, optional) – The scorer to use for assessing the quality of the output plaintext.
dist (The frequency distribution to use for scoring the Caesar step.)
- Returns:
A DataFrame with columns
keyandplaintextcontaining the best candidate keys and their corresponding decrypted plaintexts. The DataFrame is sorted by score in descending order and limited totop_nrows.- Return type:
polars.DataFrame
Notes
The function works by splitting the ciphertext into
key_lengthinterleaved subsequences and cracking each subsequence with a Caesar-cipher cracker. The resulting candidate keys are then combined using a Cartesian product to form full Vigenère keys in order of likelihood based on frequency analysis of each interleaved Caesar shift. The search is truncated aftern_trialscombinations to keep runtime reasonable for long keys.Examples
Here is an example with a relatively short ciphertext. Note that the correct decrypt is not the top result because the ciphertext is too short for very accurate decryption.
>>> Vigenere().crack("DLCFMEORCBIASTFOV", key_length=3, top_n=3) shape: (3, 3) ┌─────┬───────────────────┬──────────┐ │ key ┆ plaintext ┆ score │ │ --- ┆ --- ┆ --- │ │ str ┆ str ┆ f64 │ ╞═════╪═══════════════════╪══════════╡ │ OAY ┆ PLERMGARENICETHAV ┆ 1.135415 │ │ KEY ┆ THEVIGENERECIPHER ┆ 1.157981 │ │ OEY ┆ PHERIGANENECEPHAR ┆ 1.158325 │ └─────┴───────────────────┴──────────┘
- decrypt(ciphertext: str, key: str) str
Decrypt
ciphertextthat was encrypted with the Vigenère cipher.- Parameters:
ciphertext – The text to decrypt.
key – The decryption key. It must consist only of alphabetic characters; the function will raise a
ValueErrorif this condition is not met.
- Returns:
The original plaintext recovered from
ciphertext.- Return type:
str
Examples
>>> Vigenere().decrypt("MSZQC", "FOO") 'HELLO'
- encrypt(plaintext: str, key: str) str
Encrypt
plaintextusing the Vigenère cipher.- Parameters:
plaintext – The text to encrypt.
key – The encryption key. It must consist only of alphabetic characters; the function will raise a
ValueErrorif this condition is not met.
- Returns:
The ciphertext produced by applying the Vigenère shift to each alphabetic character of
plaintext.- Return type:
str
Examples
>>> Vigenere().encrypt("HELLO", "FOO") 'MSZQC'