1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
//! # Simple Substitution Cipher //! //! Implements the functionality for the Simple Substitution cipher. //! //! The following is an excerpt from //! [Wikipedia](https://en.wikipedia.org/wiki/Substitution_cipher#Simple_substitution). //! > Substitution of single letters separately—simple substitution—can be demonstrated by writing //! out the alphabet in some order to represent the substitution. This is termed a substitution //! alphabet. //! //! > The cipher alphabet may be shifted or reversed (creating the Caesar and Atbash ciphers, //! respectively) or scrambled in a more complex fashion, in which case it is called a mixed //! alphabet or deranged alphabet. Traditionally, mixed alphabets may be created by first writing //! out a keyword, removing repeated letters in it, then writing all the remaining letters in the //! alphabet in the usual order. use crate::{input, Cipher, CipherResult}; /// A Simple Substitution cipher implementation. pub struct Substitution { key: String, } impl Substitution { /// Takes the key for the Simple Substitution cipher and returns a /// corresponding Substitution struct. /// /// # Panics /// * If `key` is not 26 chars in length. /// * If `key` is not alphabetic. /// * If `key` contains repeated chars. pub fn new(key: &str) -> Self { assert_eq!(key.len(), 26, "`key` must be 26 chars in length"); input::is_alpha(key).expect("`key` must be alphabetic"); input::no_repeated_chars(key).expect("`key` cannot contain repeated chars"); Self { key: key.to_ascii_uppercase(), } } } impl Cipher for Substitution { /// Enciphers the given plaintext (a str reference) using the Simple /// Substitution cipher and returns the ciphertext as a `CipherResult`. /// /// # Example /// ``` /// use ciphers::{Cipher, Substitution}; /// /// let substitution = Substitution::new("PHQGIUMEAYLNOFDXJKRCVSTZWB"); /// /// let ctext = substitution.encipher("DEFENDTHEEASTWALLOFTHECASTLE"); /// assert_eq!(ctext.unwrap(), "GIUIFGCEIIPRCTPNNDUCEIQPRCNI"); /// ``` fn encipher(&self, ptext: &str) -> CipherResult { input::is_alpha(ptext)?; let ptext = ptext.to_ascii_uppercase(); let key = self.key.as_bytes(); let ctext = ptext.bytes().map(move |c| key[(c - 65) as usize]).collect(); Ok(String::from_utf8(ctext).unwrap()) } /// Deciphers the given ciphertext (a str reference) using the Simple /// Substitution cipher and returns the plaintext as a `CipherResult`. /// /// # Example /// ``` /// use ciphers::{Cipher, Substitution}; /// /// let substitution = Substitution::new("PHQGIUMEAYLNOFDXJKRCVSTZWB"); /// /// let ptext = substitution.decipher("GIUIFGCEIIPRCTPNNDUCEIQPRCNI"); /// assert_eq!(ptext.unwrap(), "DEFENDTHEEASTWALLOFTHECASTLE"); /// ``` fn decipher(&self, ctext: &str) -> CipherResult { input::is_alpha(ctext)?; let ctext = ctext.to_ascii_uppercase(); let ptext = ctext .bytes() .map(move |c| self.key.find(move |i| i == c as char).unwrap() as u8 + 65) .collect(); Ok(String::from_utf8(ptext).unwrap()) } }