use crate::common::alphabet;
use crate::common::alphabet::Alphabet;
use crate::common::cipher::Cipher;
use crate::common::keygen::cyclic_keystream;
use crate::common::substitute;
pub struct Vigenere {
key: String,
}
impl Cipher for Vigenere {
type Key = String;
type Algorithm = Vigenere;
fn new(key: String) -> Vigenere {
if key.is_empty() {
panic!("The key is empty.");
}
if !alphabet::STANDARD.is_valid(&key) {
panic!("The key contains a non-alphabetic symbol.");
}
Vigenere { key }
}
fn encrypt(&self, message: &str) -> Result<String, &'static str> {
Ok(substitute::key_substitution(
message,
&cyclic_keystream(&self.key, message),
|mi, ki| alphabet::STANDARD.modulo((mi + ki) as isize),
))
}
fn decrypt(&self, ciphertext: &str) -> Result<String, &'static str> {
Ok(substitute::key_substitution(
ciphertext,
&cyclic_keystream(&self.key, ciphertext),
|ci, ki| alphabet::STANDARD.modulo(ci as isize - ki as isize),
))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn encrypt_test() {
let message = "attackatdawn";
let v = Vigenere::new(String::from("lemon"));
assert_eq!("lxfopvefrnhr", v.encrypt(message).unwrap());
}
#[test]
fn decrypt_test() {
let ciphertext = "lxfopvefrnhr";
let v = Vigenere::new(String::from("lemon"));
assert_eq!("attackatdawn", v.decrypt(ciphertext).unwrap());
}
#[test]
fn mixed_case() {
let message = "Attack at Dawn!";
let v = Vigenere::new(String::from("giovan"));
let ciphertext = v.encrypt(message).unwrap();
let plain_text = v.decrypt(&ciphertext).unwrap();
assert_eq!(plain_text, message);
}
#[test]
fn with_utf8() {
let v = Vigenere::new(String::from("utfeightisfun"));
let message = "Peace 🗡️ Freedom and Liberty!";
let encrypted = v.encrypt(message).unwrap();
let decrypted = v.decrypt(&encrypted).unwrap();
assert_eq!(decrypted, message);
}
#[test]
fn valid_key() {
Vigenere::new(String::from("LeMon"));
}
#[test]
#[should_panic]
fn key_with_symbols() {
Vigenere::new(String::from("!em@n"));
}
#[test]
#[should_panic]
fn key_with_whitespace() {
Vigenere::new(String::from("wow this key is a real lemon"));
}
}