mini-enigma 0.3.0

#[no-std] (and no alloc) zero dependency implementation of the M3 Enigma
Documentation
use mini_enigma::state_machine::Enigma;
use mini_enigma::utils::M3;

mod common;
use common::{kat, load_enigma_settings};

#[test]
fn test_instruction_manual() {
    kat::<M3, _>("tests/data/instruction_manual.json");
}

#[test]
fn test_barbossa_a() {
    kat::<M3, _>("tests/data/operation_barbossa_a.json");
}

#[test]
fn test_barbossa_b() {
    kat::<M3, _>("tests/data/operation_barbossa_b.json");
}

#[test]
fn test_scharnhorst() {
    // The Scharnhorst message actually starts with the rotors ready to double step.
    // Since our double step implementation is not mechanical and does not 'look backwards'
    // this test adds an extra ignored char to the front of the message so the machine is in a position to double step
    let mut settings = load_enigma_settings("tests/data/scharnhorst.json");
    settings.grundstellung[2] = (settings.grundstellung[2] as u8 - 1) as char;
    settings.plaintext = "A".to_owned() + &settings.plaintext;
    settings.ciphertext = "A".to_owned() + &settings.ciphertext;
    println!("Testing {} [{}]", settings.name, settings.date.unwrap_or(0));
    let mut enigma = Enigma::new::<M3>(&settings.clone().into());
    print!("input:  ");
    let mut ct = String::new();
    for (i, ch) in settings.plaintext.chars().enumerate() {
        let bit = enigma.encrypt_char(ch);
        if i == 0 {
            continue;
        }
        ct.push(bit);
        print!("{ch}");
        if settings.ciphertext.as_bytes()[i] as char != bit {
            println!("\noutput: {ct}");
            println!("pos: {:?}", enigma.get_grundstellung());
        }
        assert_eq!(settings.ciphertext.as_bytes()[i] as char, bit)
    }
}

#[test]
fn test_practical_crypto() {
    kat::<M3, _>("tests/data/practical_cryptography.json");
}

#[test]
fn test_norrkoping() {
    kat::<M3, _>("tests/data/norrkoping.json");
}