use super::utils::DEFAULT_ROTOR_NUM;
use super::{
components::{Plugboard, Reflector, Rotor, Wheel},
utils::Letter,
};
pub struct Unset;
#[derive(Debug)]
pub struct EnigmaSettings<const ROTOR_NUM: usize = DEFAULT_ROTOR_NUM> {
pub rotors: [Rotor; ROTOR_NUM],
pub plugboard: Plugboard,
pub reflector: Reflector,
pub ringstellung: [u8; ROTOR_NUM],
pub grundstellung: [Letter; ROTOR_NUM],
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
pub struct Enigma<R, P, O, const ROTOR_NUM: usize = DEFAULT_ROTOR_NUM> {
rotors: R,
plugboard: P,
reflector: O,
}
impl Default for Enigma<Unset, Unset, Unset, DEFAULT_ROTOR_NUM> {
fn default() -> Self {
Enigma {
rotors: Unset,
plugboard: Unset,
reflector: Unset,
}
}
}
impl Enigma<Unset, Unset, Unset> {
#[must_use]
pub fn new<const ROTOR_NUM: usize>(
config: &EnigmaSettings<ROTOR_NUM>,
) -> Enigma<Wheel<ROTOR_NUM>, Plugboard, Reflector, ROTOR_NUM> {
let mut enigma = Enigma {
rotors: Wheel::new(config.rotors),
plugboard: config.plugboard,
reflector: config.reflector,
};
enigma.set_grundstellung(config.grundstellung);
enigma.set_ringstellung(config.ringstellung);
enigma
}
}
impl<AnyRotor, AnyPlugboard, AnyReflector, const ROTOR_NUM: usize>
Enigma<AnyRotor, AnyPlugboard, AnyReflector, ROTOR_NUM>
{
pub fn set_rotors(self, rotors: Wheel) -> Enigma<Wheel, AnyPlugboard, AnyReflector, ROTOR_NUM> {
Enigma {
rotors,
plugboard: self.plugboard,
reflector: self.reflector,
}
}
pub fn set_plugboard(
self,
plugboard: Plugboard,
) -> Enigma<AnyRotor, Plugboard, AnyReflector, ROTOR_NUM> {
Enigma {
rotors: self.rotors,
plugboard,
reflector: self.reflector,
}
}
pub fn set_reflector(
self,
reflector: Reflector,
) -> Enigma<AnyRotor, AnyPlugboard, Reflector, ROTOR_NUM> {
Enigma {
rotors: self.rotors,
plugboard: self.plugboard,
reflector,
}
}
}
impl<AnyPlugboard, AnyReflector, const ROTOR_NUM: usize>
Enigma<Wheel<ROTOR_NUM>, AnyPlugboard, AnyReflector, ROTOR_NUM>
{
pub fn set_grundstellung(
&mut self,
positions: [Letter; ROTOR_NUM],
) -> &mut Enigma<Wheel<ROTOR_NUM>, AnyPlugboard, AnyReflector, ROTOR_NUM> {
self.rotors.set_positions(positions);
self
}
pub fn set_ringstellung(
&mut self,
positions: [u8; ROTOR_NUM],
) -> &mut Enigma<Wheel<ROTOR_NUM>, AnyPlugboard, AnyReflector, ROTOR_NUM> {
self.rotors.set_ring_wiring_offset(positions);
self
}
pub fn get_grundstellung(&self) -> [Letter; ROTOR_NUM] {
self.rotors.get_positions()
}
}
impl<const ROTOR_NUM: usize> Enigma<Wheel<ROTOR_NUM>, Plugboard, Reflector, ROTOR_NUM> {
pub fn encrypt_letter(&mut self, letter: Letter) -> Letter {
self.rotors.step();
let left = self.rotors.forward(self.plugboard[letter]);
self.plugboard[self.rotors.backward(self.reflector[left])]
}
pub fn encrypt_char(&mut self, letter: char) -> char {
match Letter::try_from(letter) {
Ok(a) => self.encrypt_letter(a).into(),
Err(_) => letter,
}
}
}
#[cfg(test)]
mod tests {
use super::super::components::{
REFLECTOR_A, REFLECTOR_B, ROTOR_I, ROTOR_II, ROTOR_III, ROTOR_IV, ROTOR_V,
};
use super::*;
use core::str::FromStr;
#[test]
fn test_machine() {
let enigma = Enigma::default();
let enigma = enigma.set_rotors(Wheel::new([ROTOR_I, ROTOR_II, ROTOR_III]));
let enigma = enigma.set_plugboard(Plugboard::new(&[]));
let enigma = enigma.set_reflector(REFLECTOR_A);
let mut enigma = enigma.set_rotors(Wheel::new([ROTOR_III, ROTOR_II, ROTOR_I]));
enigma.encrypt_letter(Letter::A);
}
#[test]
fn test_letter() {
let mut enigma = Enigma::default()
.set_rotors(Wheel::new([ROTOR_II, ROTOR_IV, ROTOR_V]))
.set_reflector(REFLECTOR_B)
.set_plugboard(Plugboard::from_str("AV,BS,CG,DL,FU,HZ,IN,KM,OW,RX").unwrap());
enigma
.set_grundstellung([Letter::B, Letter::L, Letter::A])
.set_ringstellung([2, 21, 12]);
assert_eq!(Letter::A, enigma.encrypt_letter(Letter::E));
assert_eq!(Letter::U, enigma.encrypt_letter(Letter::D));
assert_eq!(Letter::F, enigma.encrypt_letter(Letter::P));
assert_eq!(Letter::K, enigma.encrypt_letter(Letter::U));
assert_eq!(Letter::L, enigma.encrypt_letter(Letter::D));
assert_eq!(Letter::X, enigma.encrypt_letter(Letter::N));
assert_eq!(Letter::A, enigma.encrypt_letter(Letter::R));
assert_eq!(Letter::B, enigma.encrypt_letter(Letter::G));
assert_eq!(Letter::T, enigma.encrypt_letter(Letter::Y));
assert_eq!(Letter::E, enigma.encrypt_letter(Letter::S));
}
#[test]
fn test_string() {
let mut enigma = Enigma::new(&EnigmaSettings {
rotors: [ROTOR_II, ROTOR_IV, ROTOR_V],
plugboard: Plugboard::from_str("AV,BS,CG,DL,FU,HZ,IN,KM,OW,RX").unwrap(),
reflector: REFLECTOR_B,
ringstellung: [2, 21, 12],
grundstellung: [Letter::B, Letter::L, Letter::A],
});
let input = "AUFKLXABTE";
let expected = "EDPUDNRGYS".as_bytes();
for (i, ch) in input.chars().enumerate() {
assert_eq!(expected[i] as char, enigma.encrypt_char(ch));
}
}
}