Skip to content

Instantly share code, notes, and snippets.

@hinchley
Created Jan 26, 2015
Embed
What would you like to do?
Enigma M3 Machine in PHP
<?php namespace Enigma;
class Reflector {
protected $table;
public function __construct($table) {
$this->table = array_combine(range('A', 'Z'), str_split($table));
}
public function convert($character) {
return $this->table[$character];
}
public static function select($type) {
switch ($type) {
case 'A':
return new static('EJMZALYXVBWFCRQUONTSPIKHGD');
case 'B':
return new static('YRUHQSLDPXNGOKMIEBFZCWVJAT');
case 'C':
return new static('FVPJIAOYEDRZXWGCTKUQSBNMHL');
}
throw new \InvalidArgumentException('Invalid Reflector');
}
}
class Plugboard {
protected $plugs;
public function __construct(array $plugs) {
$this->plugs = $plugs + array_flip($plugs);
}
public function convert($character) {
return isset($this->plugs[$character]) ?
$this->plugs[$character] : $character;
}
}
class Rotor {
protected $table;
protected $notch;
public function __construct($table, array $notch) {
$this->table = array_combine(range('A', 'Z'), str_split($table));
$this->notch = $notch;
}
public function step() {
$keys = array_keys($this->table);
array_unshift($keys, array_pop($keys));
$vals = array_map(function($c) {
$i = ord($c) - 1;
return $i < 65 ? 'Z' : chr($i);
}, array_values($this->table));
$this->table = array_combine($keys, $vals);
}
public function set($character) {
for ($i = 0; $i < ord($character) - 65; $i++)
$this->step();
}
public function notched() {
return in_array(current($this->table), $this->notch);
}
public function in($character) {
return $this->table[$character];
}
public function out($character) {
return array_flip($this->table)[$character];
}
public static function select($type) {
switch ($type) {
case 'I':
return new static('EKMFLGDQVZNTOWYHXUSPAIBRCJ', ['Q']);
case 'II':
return new static('AJDKSIRUXBLHWTMCQGZNPYFVOE', ['E']);
case 'III':
return new static('BDFHJLCPRTXVZNYEIWGAKMUSQO', ['V']);
case 'IV':
return new static('ESOVPZJAYQUIRHXLNFTGKDCMWB', ['J']);
case 'V':
return new static('VZBRGITYUPSDNHLXAWMJQOFECK', ['Z']);
case 'VI':
return new static('JPGVOUMFYQBENHZRDKASXLICTW', ['Z', 'M']);
case 'VII':
return new static('NZJHGRCXMYSWBOUFAIVLPEKQDT', ['Z', 'M']);
case 'VII':
return new static('FKQHTLXOCBJSPDZRAMEWNIUYGV', ['Z', 'M']);
}
throw new \InvalidArgumentException('Invalid Rotor');
}
}
class Rotors {
protected $rotors;
public function __construct(...$rotors) {
$this->rotors = array_reverse($rotors);
}
public function step() {
reset($this->rotors);
do {
current($this->rotors)->step();
} while (next($this->rotors)->notched());
}
public function in($character) {
foreach ($this->rotors as $rotor)
$character = $rotor->in($character);
return $character;
}
public function out($character) {
foreach (array_reverse($this->rotors) as $rotor)
$character = $rotor->out($character);
return $character;
}
}
class Machine {
protected $plugboard;
protected $reflector;
protected $rotors;
public function __construct($plugboard, $reflector, $rotors) {
$this->plugboard = $plugboard;
$this->reflector = $reflector;
$this->rotors = $rotors;
}
protected function clean($text) {
return preg_replace('/[^A-Z]/', '', strtoupper($text));
}
public function convert($text) {
$output = '';
foreach (str_split($this->clean($text)) as $c) {
$this->rotors->step();
$c = $this->plugboard->convert($c);
$c = $this->rotors->in($c);
$c = $this->reflector->convert($c);
$c = $this->rotors->out($c);
$c = $this->plugboard->convert($c);
$output .= $c;
}
return $output;
}
}
// example usage.
$plugboard = new Plugboard(['H' => 'F']);
$reflector = Reflector::select('B');
$i = Rotor::select('I');
$ii = Rotor::select('II');
$iii = Rotor::select('III');
$i->set('B');
$ii->set('B');
$iii->set('B');
$rotors = new Rotors($i, $ii, $iii);
$machine = new Machine($plugboard, $reflector, $rotors);
echo $machine->convert('ATTACKATDAWN');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment