use crate::{input, Cipher, CipherResult};
static PORTA_TABLEU: [[u8; 13]; 13] = [
[78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90],
[79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 78],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 78, 79],
[81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 78, 79, 80],
[82, 83, 84, 85, 86, 87, 88, 89, 90, 78, 79, 80, 81],
[83, 84, 85, 86, 87, 88, 89, 90, 78, 79, 80, 81, 82],
[84, 85, 86, 87, 88, 89, 90, 78, 79, 80, 81, 82, 83],
[85, 86, 87, 88, 89, 90, 78, 79, 80, 81, 82, 83, 84],
[86, 87, 88, 89, 90, 78, 79, 80, 81, 82, 83, 84, 85],
[87, 88, 89, 90, 78, 79, 80, 81, 82, 83, 84, 85, 86],
[88, 89, 90, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87],
[89, 90, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88],
[90, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
];
pub struct Porta {
key: String,
}
impl Porta {
pub fn new(key: &str) -> Self {
input::is_alpha(key).expect("`key` must be alphabetic");
Self {
key: key.to_ascii_uppercase(),
}
}
}
impl Cipher for Porta {
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()
.enumerate()
.map(move |(i, c)| {
let y = (key[i % key.len()] as usize - 65) / 2;
match c {
78...90 => PORTA_TABLEU[y].iter().position(|&j| j == c).unwrap() as u8 + 65,
_ => PORTA_TABLEU[y][c as usize - 65],
}
})
.collect();
Ok(String::from_utf8(ctext).unwrap())
}
fn decipher(&self, ctext: &str) -> CipherResult {
self.encipher(ctext)
}
}