| A High-Performance Enigma Machine Simulator in Rust, with Python Bindings
Link: https://lib.rs/crates/enigmar
Few machines capture the imagination like the Enigma. Used by the Wehrmacht in World War II and famously broken at Bletchley Park, its cipher logic — rotors, reflectors, plugboards, and a maddening quirk called double-stepping — is a rite of passage for anyone interested in classical cryptography.
Enigmar is an educational library that faithfully recreates the Enigma M3/M4 machines. It's written in Rust for speed and correctness, with Python bindings via PyO3 so you can experiment without leaving your notebook.
Why It's Interesting
Most Enigma simulators get the easy parts right and fumble the details. Enigmar focuses on historical accuracy:
- Rotors I–VIII and Reflectors B, C, B-thin, C-thin, matching the real wiring diagrams
- Correct double-stepping — the mechanical anomaly where the middle rotor sometimes steps twice in a row, a quirk of the real machine's ratchet mechanism that many simulators simplify away
- Reciprocal encryption — because of how the reflector works, encrypting and decrypting are literally the same operation with the same settings
- No letter self-encryption — a structural weakness of the real Enigma that cryptanalysts exploited; Enigmar reproduces it faithfully rather than "fixing" it
Under the hood, the core uses [u8; 26] lookup tables for zero-allocation, O(1) character mapping, so it's fast enough for large-scale experimentation or teaching demos.
How the Signal Path Works
Every keystroke travels through the plugboard, three rotors, a reflector, and back out through the rotors and plugboard again:
Input → Plugboard → Rotor III → Rotor II → Rotor I → Reflector
↓
Output ← Plugboard ← Rotor III ← Rotor II ← Rotor I ←────┘
Before each character is processed, the right rotor always steps. If it's sitting at its notch, the middle rotor steps too. And if the middle rotor is at its notch, both it and the left rotor step together — the double-stepping anomaly that made the real machine's period shorter than naive rotor math would suggest.
Getting Started
Rust
[dependencies]
enigmar = { path = "." }
use enigmar::EnigmaBuilder;
fn main() {
let mut machine = EnigmaBuilder::new()
.rotor("I", 0, 0)
.rotor("II", 0, 0)
.rotor("III", 0, 0)
.reflector("B")
.plugboard("AV BS CG DL FU HZ IN KM OW RX")
.build()
.unwrap();
let ciphertext = machine.process_string("HELLOWORLD");
println!("Encrypted: {}", ciphertext);
}
Python
pip install maturin
maturin develop --features extension-module
from enigmar import EnigmaBuilder
builder = EnigmaBuilder()
builder.rotor("I", 0, 0)
builder.rotor("II", 0, 0)
builder.rotor("III", 0, 0)
builder.reflector("B")
builder.plugboard("AV BS CG DL FU HZ IN KM OW RX")
machine = builder.build()
ciphertext = machine.process_string("HELLOWORLD")
print(f"Encrypted: {ciphertext}")
# Save and restore state
key = machine.export_key()
machine.import_key(key)
machine.reset()
Decryption uses the exact same settings — build a fresh machine with identical rotors, reflector, and plugboard, then run the ciphertext back through it.
API at a Glance
EnigmaBuilder
| Method | Description |
|---|---|
new() |
Create an empty builder |
.rotor(type, position, ring) |
Add a rotor, left to right. Types "I"–"VIII"
|
.reflector(type) |
Set reflector: "B", "C", "B-thin", "C-thin"
|
.plugboard(pairs) |
Set up to 13 plug pairs, e.g. "AB CD EF"
|
.build() |
Produce the EnigmaMachine
|
EnigmaMachine
| Method | Description |
|---|---|
process_string(input) |
Encrypt/decrypt; non-alpha characters are dropped |
export_key() |
Serialize state to JSON |
import_key(key) |
Restore state from JSON |
reset() |
Reset rotors to their initial positions |
Who It's For
Enigmar is built for learning: cryptography students exploring rotor ciphers, developers curious about PyO3-based Rust/Python interop, or anyone who wants to reproduce Bletchley-era encryption on modern hardware. The JSON key export also makes it easy to save, share, and reproduce exact machine configurations for teaching or testing.
Give it a try — encrypt something, export the key, and decrypt it back with a fresh machine instance. It's a small, satisfying way to see 1930s engineering behave exactly as designed.
Top comments (0)