use crate::{
cryptable::{Cipher, Crypt},
errors::CharNotInKeyError,
playfair::EMPTY_SQ_POS,
structs::{CryptModus, CryptResult, Payload},
};
use super::playfair::PlayFairKey;
pub struct TwoSquare {
top: PlayFairKey,
bottom: PlayFairKey,
}
impl TwoSquare {
pub fn new_5_to_5(key0: &str, key1: &str) -> Self {
TwoSquare {
top: PlayFairKey::new_5_to_5(key0),
bottom: PlayFairKey::new_5_to_5(key1),
}
}
pub fn new_6_to_6(key0: &str, key1: &str) -> Self {
TwoSquare {
top: PlayFairKey::new_6_to_6(key0),
bottom: PlayFairKey::new_6_to_6(key1),
}
}
}
impl Crypt for TwoSquare {
fn crypt(
&self,
a: char,
b: char,
_modus: &crate::structs::CryptModus,
) -> Result<crate::structs::CryptResult, crate::errors::CharNotInKeyError> {
let a_sq_pos = match self.top.key_map.get(&a) {
Some(p) => p,
None => EMPTY_SQ_POS,
};
let b_sq_pos = match self.bottom.key_map.get(&b) {
Some(p) => p,
None => EMPTY_SQ_POS,
};
if a_sq_pos.column == EMPTY_SQ_POS.column {
return Err(CharNotInKeyError::new(format!(
"Only chars A-Z possible - '{}' was not found in key {:?}",
a, &self.top.key
)));
} else if b_sq_pos.column == EMPTY_SQ_POS.column {
return Err(CharNotInKeyError::new(format!(
"Only chars A-Z possible - '{}' was not found in key {:?}",
b, &self.bottom.key
)));
}
let (a_crypted_idx, b_crypted_idx) = (
a_sq_pos.row * self.top.square + b_sq_pos.column,
b_sq_pos.row * self.top.square + a_sq_pos.column,
);
let a_crypted = match self.top.key.get(a_crypted_idx as usize) {
Some(s) => *s,
None => '*',
};
let b_crypted = match self.bottom.key.get(b_crypted_idx as usize) {
Some(s) => *s,
None => '*',
};
Ok(CryptResult {
a: a_crypted,
b: b_crypted,
})
}
fn crypt_payload(
&self,
payload: &str,
modus: &crate::structs::CryptModus,
) -> Result<String, crate::errors::CharNotInKeyError> {
let mut payload_iter = Payload::new(self.playload(payload));
payload_iter.crypt_payload(self, modus)
}
fn playload(&self, payload: &str) -> String {
self.top.payload(payload)
}
}
impl Cipher for TwoSquare {
fn encrypt(&self, payload: &str) -> Result<String, crate::errors::CharNotInKeyError> {
self.crypt_payload(payload, &CryptModus::Encrypt)
}
fn decrypt(&self, payload: &str) -> Result<String, crate::errors::CharNotInKeyError> {
self.crypt_payload(payload, &CryptModus::Decrypt)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_two_square_creation_key() {
let two_square = TwoSquare::new_5_to_5("EXAMPLE", "KEYWORD");
assert!(
two_square.top.key
== vec![
'E', 'X', 'A', 'M', 'P', 'L', 'B', 'C', 'D', 'F', 'G', 'H', 'I', 'K', 'N', 'O',
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Y', 'Z'
]
);
assert!(
two_square.bottom.key
== vec![
'K', 'E', 'Y', 'W', 'O', 'R', 'D', 'A', 'B', 'C', 'F', 'G', 'H', 'I', 'L', 'M',
'N', 'P', 'Q', 'S', 'T', 'U', 'V', 'X', 'Z'
]
);
}
#[test]
fn test_two_square_encrypt() {
let two_square = TwoSquare::new_5_to_5("EXAMPLE", "KEYWORD");
match two_square.encrypt("HELPMEOBIWANKENOBI") {
Ok(s) => assert!(&s == "HECMXWSRKYXPHWNODG", "{}", s),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
#[test]
fn test_two_square_decrypt() {
let two_square = TwoSquare::new_5_to_5("EXAMPLE", "KEYWORD");
match two_square.decrypt("HECMXWSRKYXPHWNODG") {
Ok(s) => assert!(s == "HELPMEOBIWANKENOBI"),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
#[test]
fn test_two_square_encrypt_second() {
let two_square = TwoSquare::new_5_to_5("UEMFUI", "NIHKGDTMSXSEMLGIFW");
match two_square.encrypt("HELPMEOBIWANKENOBI") {
Ok(s) => assert!(&s == "HENOUFHQFAANHLLPBI", "{}", s),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
#[test]
fn test_two_square_decrypt_second() {
let two_square = TwoSquare::new_5_to_5("UEMFUI", "NIHKGDTMSXSEMLGIFW");
match two_square.decrypt("HENOUFHQFAANHLLPBI") {
Ok(s) => assert!(&s == "HELPMEOBIWANKENOBI", "{}", s),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
#[test]
fn test_two_square_6_to_6_encrypt() {
let two_square = TwoSquare::new_6_to_6("example1234", "SEcret85736");
match two_square.encrypt("Ben Wade takes the 3:10 train to Yuma.") {
Ok(s) => assert!(&s == "2TQUEGPSEMESWDA52ZWSPGRESVVLPV", "{}", s),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
#[test]
fn test_two_square_6_to_6_decrypt() {
let two_square = TwoSquare::new_6_to_6("example1234", "SEcret85736");
match two_square.decrypt("2TQUEGPSEMESWDA52ZWSPGRESVVLPV") {
Ok(s) => assert!(&s == "BENWADETAKESTHE310TRAINTOYUMAX", "{}", s),
Err(e) => panic!("CharNotInKeyError {e}"),
}
}
}