use crate::utils::{find_key_for_value, text_preprocessor};
use crate::Solve;
use modinverse::modinverse;
use std::collections::HashMap;
pub struct AffineCiphertext {
ciphertext: String,
a: i32,
b: i32,
}
impl Solve for AffineCiphertext {
fn solve(&self) -> String {
decrypt(&self.ciphertext, self.a, self.b)
}
}
impl ToString for AffineCiphertext {
fn to_string(&self) -> String {
self.ciphertext.to_string()
}
}
pub fn encrypt(plaintext: &str, a: i32, b: i32) -> AffineCiphertext {
let plaintext = text_preprocessor(plaintext);
let mut alphabet: HashMap<char, i32> = HashMap::new();
let alph = "abcdefghijklmnopqrstuvwxyz";
for (index, c) in alph.chars().enumerate() {
alphabet.insert(c, index.try_into().unwrap());
}
let text_values: Vec<i32> = plaintext
.chars()
.filter(|pc| pc.is_alphabetic())
.map(|pc| *(alphabet.get(&pc).unwrap()))
.collect();
let text_values: Vec<i32> = text_values
.iter()
.map(|value| (a * value + b) % 26)
.collect();
let new_value: Vec<char> = text_values
.iter()
.map(|val| find_key_for_value(&alphabet, *val))
.collect();
let ciphertext = new_value.into_iter().collect::<String>().to_uppercase();
AffineCiphertext { ciphertext, a, b }
}
pub fn decrypt(ciphertext: &str, a: i32, b: i32) -> String {
let ciphertext = text_preprocessor(ciphertext);
let a_modinverse = modinverse(a, 26).unwrap();
let mut alphabet: HashMap<char, i32> = HashMap::new();
let alph = "abcdefghijklmnopqrstuvwxyz";
for (index, c) in alph.chars().enumerate() {
alphabet.insert(c, index.try_into().unwrap());
}
let text_values: Vec<i32> = ciphertext
.chars()
.filter(|pc| pc.is_alphabetic())
.map(|pc| *(alphabet.get(&pc).unwrap()))
.collect();
let text_values: Vec<i32> = text_values
.iter()
.map(|value| ((a_modinverse * (value - b) % 26 + 26) % 26))
.collect();
let new_value: Vec<char> = text_values
.iter()
.map(|val| find_key_for_value(&alphabet, *val))
.collect();
new_value.into_iter().collect::<String>().to_uppercase()
}