1.0
This commit is contained in:
		
						commit
						2dab896a09
					
				
					 11 changed files with 1116 additions and 0 deletions
				
			
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1 @@ | |||
| /target | ||||
							
								
								
									
										45
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,45 @@ | |||
| { | ||||
|     // Use IntelliSense to learn about possible attributes. | ||||
|     // Hover to view descriptions of existing attributes. | ||||
|     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||
|     "version": "0.2.0", | ||||
|     "configurations": [ | ||||
|         { | ||||
|             "type": "lldb", | ||||
|             "request": "launch", | ||||
|             "name": "Debug executable 'enigma'", | ||||
|             "cargo": { | ||||
|                 "args": [ | ||||
|                     "build", | ||||
|                     "--bin=enigma", | ||||
|                     "--package=enigma" | ||||
|                 ], | ||||
|                 "filter": { | ||||
|                     "name": "enigma", | ||||
|                     "kind": "bin" | ||||
|                 } | ||||
|             }, | ||||
|             "args": [], | ||||
|             "cwd": "${workspaceFolder}" | ||||
|         }, | ||||
|         { | ||||
|             "type": "lldb", | ||||
|             "request": "launch", | ||||
|             "name": "Debug unit tests in executable 'enigma'", | ||||
|             "cargo": { | ||||
|                 "args": [ | ||||
|                     "test", | ||||
|                     "--no-run", | ||||
|                     "--bin=enigma", | ||||
|                     "--package=enigma" | ||||
|                 ], | ||||
|                 "filter": { | ||||
|                     "name": "enigma", | ||||
|                     "kind": "bin" | ||||
|                 } | ||||
|             }, | ||||
|             "args": [], | ||||
|             "cwd": "${workspaceFolder}" | ||||
|         } | ||||
|     ] | ||||
| } | ||||
							
								
								
									
										224
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,224 @@ | |||
| # This file is automatically @generated by Cargo. | ||||
| # It is not intended for manual editing. | ||||
| [[package]] | ||||
| name = "aho-corasick" | ||||
| version = "0.7.15" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" | ||||
| dependencies = [ | ||||
|  "memchr", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "atty" | ||||
| version = "0.2.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" | ||||
| dependencies = [ | ||||
|  "hermit-abi", | ||||
|  "libc", | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "cfg-if" | ||||
| version = "1.0.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "enigma" | ||||
| version = "0.1.0" | ||||
| dependencies = [ | ||||
|  "log", | ||||
|  "pretty_env_logger", | ||||
|  "rand", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "env_logger" | ||||
| version = "0.7.1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" | ||||
| dependencies = [ | ||||
|  "atty", | ||||
|  "humantime", | ||||
|  "log", | ||||
|  "regex", | ||||
|  "termcolor", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "getrandom" | ||||
| version = "0.2.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
|  "libc", | ||||
|  "wasi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "hermit-abi" | ||||
| version = "0.1.18" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "humantime" | ||||
| version = "1.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" | ||||
| dependencies = [ | ||||
|  "quick-error", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "libc" | ||||
| version = "0.2.93" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "log" | ||||
| version = "0.4.14" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" | ||||
| dependencies = [ | ||||
|  "cfg-if", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "memchr" | ||||
| version = "2.3.4" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "ppv-lite86" | ||||
| version = "0.2.10" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "pretty_env_logger" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" | ||||
| dependencies = [ | ||||
|  "env_logger", | ||||
|  "log", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "quick-error" | ||||
| version = "1.2.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand" | ||||
| version = "0.8.3" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" | ||||
| dependencies = [ | ||||
|  "libc", | ||||
|  "rand_chacha", | ||||
|  "rand_core", | ||||
|  "rand_hc", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand_chacha" | ||||
| version = "0.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" | ||||
| dependencies = [ | ||||
|  "ppv-lite86", | ||||
|  "rand_core", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand_core" | ||||
| version = "0.6.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" | ||||
| dependencies = [ | ||||
|  "getrandom", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "rand_hc" | ||||
| version = "0.3.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" | ||||
| dependencies = [ | ||||
|  "rand_core", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex" | ||||
| version = "1.4.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" | ||||
| dependencies = [ | ||||
|  "aho-corasick", | ||||
|  "memchr", | ||||
|  "regex-syntax", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "regex-syntax" | ||||
| version = "0.6.23" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "termcolor" | ||||
| version = "1.1.2" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" | ||||
| dependencies = [ | ||||
|  "winapi-util", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "wasi" | ||||
| version = "0.10.2+wasi-snapshot-preview1" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi" | ||||
| version = "0.3.9" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" | ||||
| dependencies = [ | ||||
|  "winapi-i686-pc-windows-gnu", | ||||
|  "winapi-x86_64-pc-windows-gnu", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-i686-pc-windows-gnu" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-util" | ||||
| version = "0.1.5" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" | ||||
| dependencies = [ | ||||
|  "winapi", | ||||
| ] | ||||
| 
 | ||||
| [[package]] | ||||
| name = "winapi-x86_64-pc-windows-gnu" | ||||
| version = "0.4.0" | ||||
| source = "registry+https://github.com/rust-lang/crates.io-index" | ||||
| checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" | ||||
							
								
								
									
										12
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Cargo.toml
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | |||
| [package] | ||||
| name = "enigma" | ||||
| version = "0.1.0" | ||||
| authors = ["vodofrede <frederik@palmoe.dk>"] | ||||
| edition = "2018" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [dependencies] | ||||
| log = "0.4.14" | ||||
| pretty_env_logger = "0.4.0" | ||||
| rand = "0.8.3" | ||||
							
								
								
									
										67
									
								
								src/enigma.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/enigma.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,67 @@ | |||
| use std::str::FromStr; | ||||
| 
 | ||||
| use crate::*; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Enigma { | ||||
|     rotors: Vec<Rotor>, | ||||
|     plugboard: Plugboard, | ||||
|     reflector: Reflector, | ||||
| } | ||||
| 
 | ||||
| impl Enigma { | ||||
|     pub fn new(rotors: Vec<Rotor>, plugboard: Plugboard, reflector: Reflector) -> Self { | ||||
|         Enigma { | ||||
|             rotors, | ||||
|             plugboard, | ||||
|             reflector, | ||||
|         } | ||||
|     } | ||||
|     pub fn encode(&mut self, input: &str) -> Result<String, &'static str> { | ||||
|         let output: Result<String, &'static str> = input | ||||
|             .chars() | ||||
|             .map(|c| { | ||||
|                 self.rotate_rotors(); | ||||
| 
 | ||||
|                 let mut letter = Letter::from_str(&c.to_string())?; | ||||
|                 letter = self.plugboard.letter(letter); | ||||
| 
 | ||||
|                 for rotor in self.rotors.iter() { | ||||
|                     letter = rotor.forwards(letter); | ||||
|                 } | ||||
| 
 | ||||
|                 letter = self.reflector.letter(letter); | ||||
| 
 | ||||
|                 for rotor in self.rotors.iter().rev() { | ||||
|                     letter = rotor.backwards(letter); | ||||
|                 } | ||||
| 
 | ||||
|                 letter = self.plugboard.letter(letter); | ||||
| 
 | ||||
|                 Ok(char::from(letter)) | ||||
|             }) | ||||
|             .collect(); | ||||
| 
 | ||||
|         output | ||||
|     } | ||||
| 
 | ||||
|     fn rotate_rotors(&mut self) { | ||||
|         let mut rotate = true; | ||||
| 
 | ||||
|         for rotor in self.rotors.iter_mut() { | ||||
|             let rotate_next = rotor.at_notch(); | ||||
| 
 | ||||
|             if rotate { | ||||
|                 rotor.rotate(); | ||||
|             } | ||||
| 
 | ||||
|             rotate = rotate_next; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Random for Enigma { | ||||
|     fn random() -> Self { | ||||
|         todo!() | ||||
|     } | ||||
| } | ||||
							
								
								
									
										212
									
								
								src/letter.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										212
									
								
								src/letter.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,212 @@ | |||
| use crate::*; | ||||
| use rand::prelude::*; | ||||
| use std::{ | ||||
|     ops::{Add, Sub}, | ||||
|     str::FromStr, | ||||
| }; | ||||
| 
 | ||||
| pub const AMOUNT_OF_LETTERS: usize = 26; | ||||
| 
 | ||||
| #[derive(Debug, PartialEq, Eq, Hash, Copy, Clone, PartialOrd, Ord)] | ||||
| pub enum Letter { | ||||
|     A = 0, | ||||
|     B = 1, | ||||
|     C = 2, | ||||
|     D = 3, | ||||
|     E = 4, | ||||
|     F = 5, | ||||
|     G = 6, | ||||
|     H = 7, | ||||
|     I = 8, | ||||
|     J = 9, | ||||
|     K = 10, | ||||
|     L = 11, | ||||
|     M = 12, | ||||
|     N = 13, | ||||
|     O = 14, | ||||
|     P = 15, | ||||
|     Q = 16, | ||||
|     R = 17, | ||||
|     S = 18, | ||||
|     T = 19, | ||||
|     U = 20, | ||||
|     V = 21, | ||||
|     W = 22, | ||||
|     X = 23, | ||||
|     Y = 24, | ||||
|     Z = 25, | ||||
| } | ||||
| 
 | ||||
| impl Letter { | ||||
|     pub fn all() -> Vec<Letter> { | ||||
|         use Letter::*; | ||||
| 
 | ||||
|         vec![ | ||||
|             A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, | ||||
|         ] | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Add for Letter { | ||||
|     type Output = Letter; | ||||
| 
 | ||||
|     fn add(self, rhs: Self) -> Self::Output { | ||||
|         Letter::from((self as usize + rhs as usize) % 26) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Sub for Letter { | ||||
|     type Output = Letter; | ||||
| 
 | ||||
|     fn sub(self, rhs: Self) -> Self::Output { | ||||
|         let sum = (self as isize - rhs as isize).rem_euclid(26); | ||||
|         Letter::from(sum as usize) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Random for Letter { | ||||
|     fn random() -> Self { | ||||
|         let mut rng = rand::thread_rng(); | ||||
|         let num = rng.gen_range(0..AMOUNT_OF_LETTERS); | ||||
|         Letter::from(num) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<usize> for Letter { | ||||
|     fn from(n: usize) -> Self { | ||||
|         let index = n % 26; | ||||
| 
 | ||||
|         match index { | ||||
|             0 => Letter::A, | ||||
|             1 => Letter::B, | ||||
|             2 => Letter::C, | ||||
|             3 => Letter::D, | ||||
|             4 => Letter::E, | ||||
|             5 => Letter::F, | ||||
|             6 => Letter::G, | ||||
|             7 => Letter::H, | ||||
|             8 => Letter::I, | ||||
|             9 => Letter::J, | ||||
|             10 => Letter::K, | ||||
|             11 => Letter::L, | ||||
|             12 => Letter::M, | ||||
|             13 => Letter::N, | ||||
|             14 => Letter::O, | ||||
|             15 => Letter::P, | ||||
|             16 => Letter::Q, | ||||
|             17 => Letter::R, | ||||
|             18 => Letter::S, | ||||
|             19 => Letter::T, | ||||
|             20 => Letter::U, | ||||
|             21 => Letter::V, | ||||
|             22 => Letter::W, | ||||
|             23 => Letter::X, | ||||
|             24 => Letter::Y, | ||||
|             25 => Letter::Z, | ||||
|             _ => unreachable!(), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<char> for Letter { | ||||
|     fn from(c: char) -> Self { | ||||
|         match c { | ||||
|             'A' => Letter::A, | ||||
|             'B' => Letter::B, | ||||
|             'C' => Letter::C, | ||||
|             'D' => Letter::D, | ||||
|             'E' => Letter::E, | ||||
|             'F' => Letter::F, | ||||
|             'G' => Letter::G, | ||||
|             'H' => Letter::H, | ||||
|             'I' => Letter::I, | ||||
|             'J' => Letter::J, | ||||
|             'K' => Letter::K, | ||||
|             'L' => Letter::L, | ||||
|             'M' => Letter::M, | ||||
|             'N' => Letter::N, | ||||
|             'O' => Letter::O, | ||||
|             'P' => Letter::P, | ||||
|             'Q' => Letter::Q, | ||||
|             'R' => Letter::R, | ||||
|             'S' => Letter::S, | ||||
|             'T' => Letter::T, | ||||
|             'U' => Letter::U, | ||||
|             'V' => Letter::V, | ||||
|             'W' => Letter::W, | ||||
|             'X' => Letter::X, | ||||
|             'Y' => Letter::Y, | ||||
|             'Z' => Letter::Z, | ||||
|             _ => panic!("Tried to parse unknown letter: '{}'", c), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl FromStr for Letter { | ||||
|     type Err = &'static str; | ||||
| 
 | ||||
|     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||
|         match s { | ||||
|             "A" => Ok(Letter::A), | ||||
|             "B" => Ok(Letter::B), | ||||
|             "C" => Ok(Letter::C), | ||||
|             "D" => Ok(Letter::D), | ||||
|             "E" => Ok(Letter::E), | ||||
|             "F" => Ok(Letter::F), | ||||
|             "G" => Ok(Letter::G), | ||||
|             "H" => Ok(Letter::H), | ||||
|             "I" => Ok(Letter::I), | ||||
|             "J" => Ok(Letter::J), | ||||
|             "K" => Ok(Letter::K), | ||||
|             "L" => Ok(Letter::L), | ||||
|             "M" => Ok(Letter::M), | ||||
|             "N" => Ok(Letter::N), | ||||
|             "O" => Ok(Letter::O), | ||||
|             "P" => Ok(Letter::P), | ||||
|             "Q" => Ok(Letter::Q), | ||||
|             "R" => Ok(Letter::R), | ||||
|             "S" => Ok(Letter::S), | ||||
|             "T" => Ok(Letter::T), | ||||
|             "U" => Ok(Letter::U), | ||||
|             "V" => Ok(Letter::V), | ||||
|             "W" => Ok(Letter::W), | ||||
|             "X" => Ok(Letter::X), | ||||
|             "Y" => Ok(Letter::Y), | ||||
|             "Z" => Ok(Letter::Z), | ||||
|             _ => Err("Failed to parse string as letter"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<Letter> for char { | ||||
|     fn from(letter: Letter) -> Self { | ||||
|         match letter { | ||||
|             Letter::A => 'A', | ||||
|             Letter::B => 'B', | ||||
|             Letter::C => 'C', | ||||
|             Letter::D => 'D', | ||||
|             Letter::E => 'E', | ||||
|             Letter::F => 'F', | ||||
|             Letter::G => 'G', | ||||
|             Letter::H => 'H', | ||||
|             Letter::I => 'I', | ||||
|             Letter::J => 'J', | ||||
|             Letter::K => 'K', | ||||
|             Letter::L => 'L', | ||||
|             Letter::M => 'M', | ||||
|             Letter::N => 'N', | ||||
|             Letter::O => 'O', | ||||
|             Letter::P => 'P', | ||||
|             Letter::Q => 'Q', | ||||
|             Letter::R => 'R', | ||||
|             Letter::S => 'S', | ||||
|             Letter::T => 'T', | ||||
|             Letter::U => 'U', | ||||
|             Letter::V => 'V', | ||||
|             Letter::W => 'W', | ||||
|             Letter::X => 'X', | ||||
|             Letter::Y => 'Y', | ||||
|             Letter::Z => 'Z', | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										203
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/main.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,203 @@ | |||
| mod enigma; | ||||
| mod letter; | ||||
| mod plugboard; | ||||
| mod random; | ||||
| mod reflector; | ||||
| mod rotor; | ||||
| 
 | ||||
| pub use enigma::*; | ||||
| pub use letter::*; | ||||
| pub use plugboard::*; | ||||
| pub use random::*; | ||||
| pub use reflector::*; | ||||
| pub use rotor::*; | ||||
| 
 | ||||
| use std::io; | ||||
| 
 | ||||
| fn main() { | ||||
|     #[cfg(debug_assertions)] | ||||
|     pretty_env_logger::init(); | ||||
| 
 | ||||
|     let rotors = choose_rotors(); | ||||
|     let plugboard = choose_plugboard(); | ||||
|     let reflector = choose_reflector(); | ||||
|     println!("Plugboard configuration: {}", plugboard); | ||||
|     let enigma_machine = Enigma::new(rotors, plugboard, reflector); | ||||
| 
 | ||||
|     loop { | ||||
|         let mut enigma_machine = enigma_machine.clone(); | ||||
| 
 | ||||
|         println!("Input some text to encrypt:"); | ||||
| 
 | ||||
|         let input = clean_input(get_input_from_stdin()); | ||||
|         let output = enigma_machine.encode(&input); | ||||
| 
 | ||||
|         match output { | ||||
|             Ok(output) => println!("Input: {}\nOutput: {}", input, output), | ||||
|             Err(e) => println!("Wrong input: {}", e), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn choose_rotors() -> Vec<Rotor> { | ||||
|     let mut rotors = vec![]; | ||||
| 
 | ||||
|     while rotors.is_empty() { | ||||
|         rotors.clear(); | ||||
|         println!("Available rotors:"); | ||||
|         for rotor in Rotor::all() { | ||||
|             println!("\t{}", rotor.variant); | ||||
|         } | ||||
|         println!("Choose rotors (comma-separated, right to left):"); | ||||
|         let input = clean_input(get_input_from_stdin()); | ||||
| 
 | ||||
|         for choice in input.split(',') { | ||||
|             let rotor = match choice { | ||||
|                 "I" => Rotor::variant(RotorVariant::I), | ||||
|                 "II" => Rotor::variant(RotorVariant::II), | ||||
|                 "III" => Rotor::variant(RotorVariant::III), | ||||
|                 "IV" => Rotor::variant(RotorVariant::IV), | ||||
|                 "V" => Rotor::variant(RotorVariant::V), | ||||
|                 "VI" => Rotor::variant(RotorVariant::VI), | ||||
|                 "VII" => Rotor::variant(RotorVariant::VII), | ||||
|                 "VIII" => Rotor::variant(RotorVariant::VIII), | ||||
|                 "IDENTITY" => Rotor::variant(RotorVariant::Identity), | ||||
|                 _ => { | ||||
|                     println!("Invalid rotor choice: {}", choice); | ||||
|                     break; | ||||
|                 } | ||||
|             }; | ||||
| 
 | ||||
|             rotors.push(rotor); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     rotors | ||||
| } | ||||
| 
 | ||||
| fn choose_plugboard() -> Plugboard { | ||||
|     let mut plugboard = None; | ||||
| 
 | ||||
|     while plugboard.is_none() { | ||||
|         println!("Available plugboards:"); | ||||
|         println!("\tRandom"); | ||||
|         println!("\tIdentity"); | ||||
|         println!("Choose plugboard (only one):"); | ||||
|         let input = clean_input(get_input_from_stdin()); | ||||
| 
 | ||||
|         plugboard = match &input[..] { | ||||
|             "IDENTITY" => Some(Plugboard::identity()), | ||||
|             "RANDOM" => Some(Plugboard::random()), | ||||
|             _ => { | ||||
|                 println!("Invalid plugboard choice: {}", input); | ||||
|                 None | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     plugboard.unwrap() | ||||
| } | ||||
| 
 | ||||
| fn choose_reflector() -> Reflector { | ||||
|     let mut reflector = None; | ||||
| 
 | ||||
|     while reflector.is_none() { | ||||
|         println!("Available reflectors:"); | ||||
|         for reflector in Reflector::all() { | ||||
|             println!("\t{}", reflector.variant); | ||||
|         } | ||||
|         println!("Choose reflector (only one):"); | ||||
|         let input = clean_input(get_input_from_stdin()); | ||||
| 
 | ||||
|         reflector = match &input[..] { | ||||
|             "A" => Some(Reflector::variant(ReflectorVariant::A)), | ||||
|             "B" => Some(Reflector::variant(ReflectorVariant::B)), | ||||
|             "C" => Some(Reflector::variant(ReflectorVariant::C)), | ||||
|             "BETA" => Some(Reflector::variant(ReflectorVariant::Beta)), | ||||
|             "GAMMA" => Some(Reflector::variant(ReflectorVariant::Gamma)), | ||||
|             "BTHIN" => Some(Reflector::variant(ReflectorVariant::BThin)), | ||||
|             "CTHIN" => Some(Reflector::variant(ReflectorVariant::CThin)), | ||||
|             "IDENTITY" => Some(Reflector::variant(ReflectorVariant::Identity)), | ||||
|             _ => { | ||||
|                 println!("Invalid reflector choice: {}", input); | ||||
|                 None | ||||
|             } | ||||
|         }; | ||||
|     } | ||||
| 
 | ||||
|     reflector.unwrap() | ||||
| } | ||||
| 
 | ||||
| fn get_input_from_stdin() -> String { | ||||
|     let mut input = String::new(); | ||||
|     io::stdin().read_line(&mut input).unwrap(); | ||||
|     input | ||||
| } | ||||
| 
 | ||||
| fn clean_input(input: String) -> String { | ||||
|     input | ||||
|         .trim() | ||||
|         .chars() | ||||
|         .filter(|c| c != &' ' && c != &'\r' && c != &'\n') | ||||
|         .collect::<String>() | ||||
|         .to_uppercase() | ||||
| } | ||||
| 
 | ||||
| #[cfg(test)] | ||||
| mod tests { | ||||
|     use super::*; | ||||
| 
 | ||||
|     #[test] | ||||
|     fn enigma_machine_encodes_correctly() { | ||||
|         let rotors = vec![ | ||||
|             Rotor::variant(RotorVariant::I), | ||||
|             Rotor::variant(RotorVariant::II), | ||||
|             Rotor::variant(RotorVariant::III), | ||||
|         ]; | ||||
|         let plugboard = Plugboard::identity(); | ||||
|         let reflector = Reflector::variant(ReflectorVariant::B); | ||||
|         let enigma_machine = Enigma::new(rotors, plugboard, reflector); | ||||
| 
 | ||||
|         let mut em1 = enigma_machine.clone(); | ||||
|         let mut em2 = enigma_machine.clone(); | ||||
| 
 | ||||
|         println!("Encoding string"); | ||||
|         let result = em1 | ||||
|             .encode("MAGNUSERPISSEDAARLIGTILLEAGUEOFLEGENDS") | ||||
|             .unwrap(); | ||||
|         assert_eq!(result, "HTMPRVHFYZUHSANJWQCCAOHUTDRICUYUJJTHBE"); | ||||
| 
 | ||||
|         println!("Decoding string"); | ||||
|         let result = em2 | ||||
|             .encode("HTMPRVHFYZUHSANJWQCCAOHUTDRICUYUJJTHBE") | ||||
|             .unwrap(); | ||||
|         assert_eq!(result, "MAGNUSERPISSEDAARLIGTILLEAGUEOFLEGENDS"); | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn random_plugboard_is_complete() { | ||||
|         let plugboard = Plugboard::random(); | ||||
| 
 | ||||
|         for letter in Letter::all() { | ||||
|             println!("Testing if '{:?}' is mapped in plugboard", letter); | ||||
|             plugboard.letter(letter); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     #[test] | ||||
|     fn rotor_rotates_as_expected() { | ||||
|         let mut rotor = Rotor::variant(RotorVariant::Identity); | ||||
| 
 | ||||
|         println!("{:?}", rotor.mappings); | ||||
|         assert_eq!(rotor.forwards(Letter::A), Letter::A); | ||||
|         rotor.rotate(); | ||||
|         assert_eq!(rotor.forwards(Letter::A), Letter::A); | ||||
| 
 | ||||
|         for _ in 0..26 { | ||||
|             rotor.rotate(); | ||||
|         } | ||||
| 
 | ||||
|         println!("{:?}", rotor.mappings); | ||||
|         assert_eq!(rotor.forwards(Letter::A), Letter::A); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										122
									
								
								src/plugboard.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										122
									
								
								src/plugboard.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,122 @@ | |||
| use crate::*; | ||||
| use rand::prelude::*; | ||||
| use std::{collections::HashMap, fmt}; | ||||
| 
 | ||||
| // MUST be less than total amount of letters divided by two
 | ||||
| const CABLES: usize = 10; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Plugboard { | ||||
|     mappings: Vec<Letter>, | ||||
| } | ||||
| 
 | ||||
| impl Plugboard { | ||||
|     pub fn new(mappings: Vec<Letter>) -> Self { | ||||
|         Plugboard { mappings } | ||||
|     } | ||||
| 
 | ||||
|     pub fn identity() -> Self { | ||||
|         let mappings = vec![ | ||||
|             Letter::A, | ||||
|             Letter::B, | ||||
|             Letter::C, | ||||
|             Letter::D, | ||||
|             Letter::E, | ||||
|             Letter::F, | ||||
|             Letter::G, | ||||
|             Letter::H, | ||||
|             Letter::I, | ||||
|             Letter::J, | ||||
|             Letter::K, | ||||
|             Letter::L, | ||||
|             Letter::M, | ||||
|             Letter::N, | ||||
|             Letter::O, | ||||
|             Letter::P, | ||||
|             Letter::Q, | ||||
|             Letter::R, | ||||
|             Letter::S, | ||||
|             Letter::T, | ||||
|             Letter::U, | ||||
|             Letter::V, | ||||
|             Letter::W, | ||||
|             Letter::X, | ||||
|             Letter::Y, | ||||
|             Letter::Z, | ||||
|         ]; | ||||
| 
 | ||||
|         Plugboard::new(mappings) | ||||
|     } | ||||
| 
 | ||||
|     pub fn index(&self, index: usize) -> usize { | ||||
|         *self.mappings.get(index).expect( | ||||
|             &format!( | ||||
|                 "Switchboard is missing mapping for a letter: {:?}", | ||||
|                 Letter::from(index) | ||||
|             ) | ||||
|             .to_string(), | ||||
|         ) as usize | ||||
|     } | ||||
| 
 | ||||
|     pub fn letter(&self, letter: Letter) -> Letter { | ||||
|         Letter::from(self.index(letter as usize)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for Plugboard { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         let mut pairs = HashMap::new(); | ||||
| 
 | ||||
|         for (i, mapping) in self.mappings.iter().enumerate() { | ||||
|             let left_letter = Letter::from(i); | ||||
|             let right_letter = *mapping; | ||||
| 
 | ||||
|             if left_letter != right_letter | ||||
|                 && !pairs.get(&left_letter).is_some() | ||||
|                 && !pairs.get(&right_letter).is_some() | ||||
|             { | ||||
|                 pairs.insert(left_letter, right_letter); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         let mut s = String::new(); | ||||
|         if pairs.is_empty() { | ||||
|             s = "Identity".to_string(); | ||||
|         } | ||||
| 
 | ||||
|         for (left_letter, right_letter) in pairs.iter() { | ||||
|             s = format!("{:?}{:?} {}", left_letter, right_letter, s); | ||||
|         } | ||||
| 
 | ||||
|         f.write_str(&s) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Random for Plugboard { | ||||
|     fn random() -> Self { | ||||
|         let mut mappings = vec![Letter::A; AMOUNT_OF_LETTERS]; | ||||
|         let mut rng = rand::thread_rng(); | ||||
| 
 | ||||
|         let mut input = Letter::all(); | ||||
|         input.shuffle(&mut rng); | ||||
|         input.truncate(CABLES); | ||||
| 
 | ||||
|         let mut output: Vec<Letter> = Letter::all() | ||||
|             .iter() | ||||
|             .filter(|l| !input.contains(l)) | ||||
|             .cloned() | ||||
|             .collect(); | ||||
|         let remaining = output.split_off(CABLES); | ||||
| 
 | ||||
|         for (input, output) in input.iter().zip(output.iter()) { | ||||
|             mappings.insert(*input as usize, *output); | ||||
|             mappings.insert(*output as usize, *input); | ||||
|         } | ||||
| 
 | ||||
|         for letter in remaining { | ||||
|             mappings.insert(letter as usize, letter); | ||||
|         } | ||||
| 
 | ||||
|         Plugboard::new(mappings) | ||||
|     } | ||||
| } | ||||
							
								
								
									
										3
									
								
								src/random.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/random.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| pub trait Random { | ||||
|     fn random() -> Self; | ||||
| } | ||||
							
								
								
									
										96
									
								
								src/reflector.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								src/reflector.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,96 @@ | |||
| use crate::*; | ||||
| use std::fmt; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Reflector { | ||||
|     pub variant: ReflectorVariant, | ||||
|     mappings: Vec<Letter>, | ||||
| } | ||||
| 
 | ||||
| impl Reflector { | ||||
|     pub fn variant(variant: ReflectorVariant) -> Self { | ||||
|         let mappings = match variant { | ||||
|             ReflectorVariant::Identity => mappings(VARIANT_IDENTITY), | ||||
|             ReflectorVariant::Beta => mappings(VARIANT_BETA), | ||||
|             ReflectorVariant::Gamma => mappings(VARIANT_GAMMA), | ||||
|             ReflectorVariant::A => mappings(VARIANT_A), | ||||
|             ReflectorVariant::B => mappings(VARIANT_B), | ||||
|             ReflectorVariant::C => mappings(VARIANT_C), | ||||
|             ReflectorVariant::BThin => mappings(VARIANT_B_THIN), | ||||
|             ReflectorVariant::CThin => mappings(VARIANT_C_THIN), | ||||
|         }; | ||||
| 
 | ||||
|         Reflector { variant, mappings } | ||||
|     } | ||||
| 
 | ||||
|     pub fn all() -> Vec<Reflector> { | ||||
|         vec![ | ||||
|             Reflector::variant(ReflectorVariant::A), | ||||
|             Reflector::variant(ReflectorVariant::B), | ||||
|             Reflector::variant(ReflectorVariant::C), | ||||
|             Reflector::variant(ReflectorVariant::Beta), | ||||
|             Reflector::variant(ReflectorVariant::Gamma), | ||||
|             Reflector::variant(ReflectorVariant::BThin), | ||||
|             Reflector::variant(ReflectorVariant::CThin), | ||||
|             Reflector::variant(ReflectorVariant::Identity), | ||||
|         ] | ||||
|     } | ||||
| 
 | ||||
|     pub fn index(&self, letter: usize) -> usize { | ||||
|         *self | ||||
|             .mappings | ||||
|             .get(letter) | ||||
|             .expect(&format!("Reflector is missing mapping for a letter: {:?}", letter).to_string()) | ||||
|             as usize | ||||
|     } | ||||
| 
 | ||||
|     pub fn letter(&self, letter: Letter) -> Letter { | ||||
|         Letter::from(self.index(letter as usize)) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const VARIANT_IDENTITY: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||
| const VARIANT_BETA: &'static str = "LEYJVCNIXWPBQMDRTAKZGFUHOS"; | ||||
| const VARIANT_GAMMA: &'static str = "FSOKANUERHMBTIYCWLQPZXVGJD"; | ||||
| const VARIANT_A: &'static str = "EJMZALYXVBWFCRQUONTSPIKHGD"; | ||||
| const VARIANT_B: &'static str = "YRUHQSLDPXNGOKMIEBFZCWVJAT"; | ||||
| const VARIANT_C: &'static str = "FVPJIAOYEDRZXWGCTKUQSBNMHL"; | ||||
| const VARIANT_B_THIN: &'static str = "ENKQAUYWJICOPBLMDXZVFTHRGS"; | ||||
| const VARIANT_C_THIN: &'static str = "RDOBJNTKVEHMLFCWZAXGYIPSUQ"; | ||||
| 
 | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum ReflectorVariant { | ||||
|     Identity, | ||||
|     Beta, | ||||
|     Gamma, | ||||
|     A, | ||||
|     B, | ||||
|     C, | ||||
|     BThin, | ||||
|     CThin, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for ReflectorVariant { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         match self { | ||||
|             ReflectorVariant::Identity => f.write_str("Identity"), | ||||
|             ReflectorVariant::Beta => f.write_str("Beta"), | ||||
|             ReflectorVariant::Gamma => f.write_str("Gamma"), | ||||
|             ReflectorVariant::A => f.write_str("A"), | ||||
|             ReflectorVariant::B => f.write_str("B"), | ||||
|             ReflectorVariant::C => f.write_str("C"), | ||||
|             ReflectorVariant::BThin => f.write_str("B Thin"), | ||||
|             ReflectorVariant::CThin => f.write_str("C Thin"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn mappings(input: &'static str) -> Vec<Letter> { | ||||
|     let mut mappings = vec![]; | ||||
| 
 | ||||
|     for c in input.chars() { | ||||
|         mappings.push(Letter::from(c)); | ||||
|     } | ||||
| 
 | ||||
|     mappings | ||||
| } | ||||
							
								
								
									
										131
									
								
								src/rotor.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								src/rotor.rs
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,131 @@ | |||
| use crate::*; | ||||
| use std::fmt; | ||||
| 
 | ||||
| #[derive(Debug, Clone)] | ||||
| pub struct Rotor { | ||||
|     pub variant: RotorVariant, | ||||
|     pub mappings: Vec<Letter>, | ||||
|     pub position: Letter, | ||||
|     pub notches: Vec<Letter>, | ||||
| } | ||||
| 
 | ||||
| impl Rotor { | ||||
|     pub fn variant(variant: RotorVariant) -> Self { | ||||
|         let (mappings, notches) = match variant { | ||||
|             RotorVariant::Identity => (mappings(IDENTITY), vec![Letter::Z]), | ||||
|             RotorVariant::I => (mappings(VARIANT_I), vec![Letter::Q]), | ||||
|             RotorVariant::II => (mappings(VARIANT_II), vec![Letter::E]), | ||||
|             RotorVariant::III => (mappings(VARIANT_III), vec![Letter::V]), | ||||
|             RotorVariant::IV => (mappings(VARIANT_IV), vec![Letter::J]), | ||||
|             RotorVariant::V => (mappings(VARIANT_V), vec![Letter::Z]), | ||||
|             RotorVariant::VI => (mappings(VARIANT_VI), vec![Letter::Z, Letter::M]), | ||||
|             RotorVariant::VII => (mappings(VARIANT_VII), vec![Letter::Z, Letter::M]), | ||||
|             RotorVariant::VIII => (mappings(VARIANT_VIII), vec![Letter::Z, Letter::M]), | ||||
|         }; | ||||
| 
 | ||||
|         let position = Letter::A; | ||||
| 
 | ||||
|         Rotor { | ||||
|             variant, | ||||
|             mappings, | ||||
|             position, | ||||
|             notches, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn all() -> Vec<Rotor> { | ||||
|         vec![ | ||||
|             Rotor::variant(RotorVariant::I), | ||||
|             Rotor::variant(RotorVariant::II), | ||||
|             Rotor::variant(RotorVariant::III), | ||||
|             Rotor::variant(RotorVariant::IV), | ||||
|             Rotor::variant(RotorVariant::V), | ||||
|             Rotor::variant(RotorVariant::VI), | ||||
|             Rotor::variant(RotorVariant::VII), | ||||
|             Rotor::variant(RotorVariant::VIII), | ||||
|             Rotor::variant(RotorVariant::Identity), | ||||
|         ] | ||||
|     } | ||||
| 
 | ||||
|     pub fn set_position(&mut self, position: Letter) { | ||||
|         self.position = position; | ||||
|     } | ||||
| 
 | ||||
|     pub fn forwards(&self, letter: Letter) -> Letter { | ||||
|         *self | ||||
|             .mappings | ||||
|             .get((letter + self.position) as usize) | ||||
|             .expect(&format!("Rotor is missing mapping for a letter: {:?}", letter).to_string()) | ||||
|             - self.position | ||||
|     } | ||||
| 
 | ||||
|     pub fn backwards(&self, letter: Letter) -> Letter { | ||||
|         Letter::from( | ||||
|             self.mappings | ||||
|                 .iter() | ||||
|                 .enumerate() | ||||
|                 .filter(|(_, l)| (**l - self.position) == letter) | ||||
|                 .next() | ||||
|                 .unwrap() | ||||
|                 .0, | ||||
|         ) - self.position | ||||
|     } | ||||
| 
 | ||||
|     pub fn at_notch(&self) -> bool { | ||||
|         self.notches.contains(&self.position) | ||||
|     } | ||||
| 
 | ||||
|     pub fn rotate(&mut self) { | ||||
|         self.position = Letter::from((self.position as usize + 1) % AMOUNT_OF_LETTERS); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| const IDENTITY: &'static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||||
| const VARIANT_I: &'static str = "EKMFLGDQVZNTOWYHXUSPAIBRCJ"; | ||||
| const VARIANT_II: &'static str = "AJDKSIRUXBLHWTMCQGZNPYFVOE"; | ||||
| const VARIANT_III: &'static str = "BDFHJLCPRTXVZNYEIWGAKMUSQO"; | ||||
| const VARIANT_IV: &'static str = "ESOVPZJAYQUIRHXLNFTGKDCMWB"; | ||||
| const VARIANT_V: &'static str = "VZBRGITYUPSDNHLXAWMJQOFECK"; | ||||
| const VARIANT_VI: &'static str = "JPGVOUMFYQBENHZRDKASXLICTW"; | ||||
| const VARIANT_VII: &'static str = "NZJHGRCXMYSWBOUFAIVLPEKQDT"; | ||||
| const VARIANT_VIII: &'static str = "FKQHTLXOCBJSPDZRAMEWNIUYGV"; | ||||
| 
 | ||||
| #[non_exhaustive] | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub enum RotorVariant { | ||||
|     Identity, | ||||
|     I, | ||||
|     II, | ||||
|     III, | ||||
|     IV, | ||||
|     V, | ||||
|     VI, | ||||
|     VII, | ||||
|     VIII, | ||||
| } | ||||
| 
 | ||||
| impl fmt::Display for RotorVariant { | ||||
|     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||
|         match self { | ||||
|             RotorVariant::Identity => f.write_str("Identity"), | ||||
|             RotorVariant::I => f.write_str("I"), | ||||
|             RotorVariant::II => f.write_str("II"), | ||||
|             RotorVariant::III => f.write_str("III"), | ||||
|             RotorVariant::IV => f.write_str("IV"), | ||||
|             RotorVariant::V => f.write_str("V"), | ||||
|             RotorVariant::VI => f.write_str("VI"), | ||||
|             RotorVariant::VII => f.write_str("VII"), | ||||
|             RotorVariant::VIII => f.write_str("VIII"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| fn mappings(input: &'static str) -> Vec<Letter> { | ||||
|     let mut mappings = vec![]; | ||||
| 
 | ||||
|     for c in input.chars() { | ||||
|         mappings.push(Letter::from(c)); | ||||
|     } | ||||
| 
 | ||||
|     mappings | ||||
| } | ||||
		Loading…
	
		Reference in a new issue