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 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
//! # Affine Cipher //! //! Implements the functionality for the Affine cipher. //! //! The following is an excerpt from [Wikipedia](https://en.wikipedia.org/wiki/Affine_cipher). //! > The affine cipher is a type of monoalphabetic substitution cipher, wherein each letter in an //! alphabet is mapped to its numeric equivalent, encrypted using a simple mathematical function, //! and converted back to a letter. //! //! > The formula used means that each letter encrypts to one other letter, and back again, meaning //! the cipher is essentially a standard substitution cipher with a rule governing which letter goes //! to which. //! //! > As such, it has the weaknesses of all substitution ciphers. Each letter is enciphered with the //! function (ax + b) mod 26, where b is the magnitude of the shift. use crate::{input, Cipher, CipherResult}; static RELATIVE_PRIMES: [i32; 12] = [1, 3, 5, 7, 9, 11, 15, 17, 19, 21, 23, 25]; /// An Affine cipher implementation. pub struct Affine { a: i32, b: i32, } impl Affine { /// Takes the two keys for the Affine cipher and returns a /// corresponding Affine struct. /// /// # Panics /// * If `a` is outside the range [1, 26). /// * If `b` is outside the range [0, 26). /// * If `a` is not relatively prime to 26. pub fn new(a: i32, b: i32) -> Self { assert!(0 < a && a < 26, "`a` must be in the range [1, 26)"); assert!(0 <= b && b < 26, "`b` must be in the range [0, 26)"); assert!( RELATIVE_PRIMES.contains(&a), "`a` must be relatively prime to 26" ); Self { a, b } } } impl Cipher for Affine { /// Enciphers the given plaintext (a str reference) using the Affine cipher /// and returns the ciphertext as a `CipherResult`. /// /// # Example /// ``` /// use ciphers::{Cipher, Affine}; /// /// let affine = Affine::new(7, 11); /// /// let ctext = affine.encipher("DEFENDTHEEASTWALLOFTHECASTLE"); /// assert_eq!(ctext.unwrap(), "GNUNYGOINNLHOJLKKFUOINZLHOKN"); /// ``` fn encipher(&self, ptext: &str) -> CipherResult { input::is_alpha(ptext)?; let ptext = ptext.to_ascii_uppercase(); let ctext = ptext .bytes() .map(move |c| ((self.a * (c as i32 - 65) + self.b) % 26) as u8 + 65) .collect(); Ok(String::from_utf8(ctext).unwrap()) } /// Deciphers the given ciphertext (a str reference) using the Affine cipher /// and returns the plaintext as a `CipherResult`. /// /// # Example /// ``` /// use ciphers::{Cipher, Affine}; /// /// let affine = Affine::new(7, 11); /// /// let ptext = affine.decipher("GNUNYGOINNLHOJLKKFUOINZLHOKN"); /// assert_eq!(ptext.unwrap(), "DEFENDTHEEASTWALLOFTHECASTLE"); /// ``` fn decipher(&self, ctext: &str) -> CipherResult { input::is_alpha(ctext)?; let ctext = ctext.to_ascii_uppercase(); let a_inv = invmod(self.a, 26).unwrap(); let ptext = ctext .bytes() .map(move |c| (((a_inv * (c as i32 - 65 - self.b)) % 26 + 26) % 26) as u8 + 65) .collect(); Ok(String::from_utf8(ptext).unwrap()) } } fn egcd(a: i32, b: i32) -> (i32, i32, i32) { match a { 0 => (b, 0, 1), _ => { let (g, x, y) = egcd(b % a, a); (g, y - (b / a) * x, x) } } } fn invmod(a: i32, m: i32) -> Option<i32> { let (g, x, _) = egcd(a, m); match g { 1 => Some((x % m + m) % m), _ => None, } }