Implementa la macchina Enigma


18

La macchina Enigma è una macchina di cifratura abbastanza complessa utilizzata dai tedeschi e da altri per crittografare i loro messaggi. Il tuo compito è implementare questa macchina *.

Passaggio 1, rotazione

La nostra macchina per enigmi ha 3 slot per rotori e 5 rotori disponibili per ciascuno di questi slot. Ogni rotore ha 26 diverse posizioni possibili (da Aa Z). Ogni rotore ha una posizione di tacca predefinita :

Rotor  Notch
------------
1      Q
2      E
3      V
4      J
5      Z

Alla pressione dei tasti si verificano i seguenti passaggi:

  1. Il rotore nello slot 1 ruota
  2. Se il rotore nello slot 1 si sposta oltre la sua tacca, quindi ruota il rotore nello slot 2.
  3. Se il rotore nello slot 2 è nella sua tacca (ma non si è semplicemente spostato lì), entrambi i rotori 2 e 3 ruotano una volta.

Se stiamo usando rotori 1,3,5 e sono in posizioni P,U,Hallora la sequenza di posizioni è: P,U,H> Q,U,H> R,V,H>S,W,I

Passaggio 2, Sostituzione

Ciascuno dei rotori esegue una semplice sostituzione del carattere. Di seguito è riportato un grafico di ciascuno dei rotori nella Aposizione:

  ABCDEFGHIJKLMNOPQRSTUVWXYZ
  --------------------------
1 EKMFLGDQVZNTOWYHXUSPAIBRCJ
2 AJDKSIRUXBLHWTMCQGZNPYFVOE
3 BDFHJLCPRTXVZNYEIWGAKMUSQO
4 ESOVPZJAYQUIRHXLNFTGKDCMWB
5 VZBRGITYUPSDNHLXAWMJQOFECK
R YRUHQSLDPXNGOKMIEBFZCWVJAT

Rotore 1 in posizione T è PAIBRCJEKMFLGDQVZNTOWYHXUS, che sostituire la lettera Cper I.

Dopo che i tre rotori eseguono la loro sostituzione, il riflettore viene colpito (elencato come Rsopra). Esegue la propria sostituzione e quindi riflette il segnale indietro attraverso i rotori. I rotori eseguono quindi una sostituzione inversa in ordine inverso.

Sostituzione inversa significa che invece di sostituire il Rotore 1 Acon E, sostituisce EconA

Gli slot sono riempiti con rotori 1,2,3 tutti in posizione A. La lettera Qsegue il percorso Q>X>V>Mattraverso i rotori. Mriflette a O, che segue quindi il percorso inverso di O>Z>S>S. Pertanto, Aviene sostituito con S.

Input Output

Sei passato:

  1. Un elenco di 3 rotori (come numeri interi)
  2. Un elenco di 3 posizioni iniziali del rotore (come lettere)
  3. Una stringa che deve essere crittografata.

Puoi presumere che il tuo input sarà ben formato e che tutti i caratteri saranno lettere maiuscole, senza spazi.

È necessario restituire la stringa crittografata.

È possibile accettare facoltativamente rotori, tacche e riflettori come input. Per quelli che non lo fanno possono togliere 95 byte dal loro punteggio, come95 = ceil(log2(26 letters ^(26*6 rotors +5 notches))/8 bytes)

Casi test

Rotor Position Input              Output
4,1,5 H,P,G    AAAAAAAAA          RPWKMBZLN
1,2,3 A,A,A    PROGRAMMINGPUZZLES RTFKHDOVZSXTRMVPFC
1,2,3 A,A,A    RTFKHDOVZSXTRMVPFC PROGRAMMINGPUZZLES
2,5,3 U,L,I    GIBDZNJLGXZ        UNCRACKABLE

La mia implementazione può essere trovata su Github . L'ho provato, ma potrei avere dei bug nella mia implementazione (il che significherebbe che i miei casi di test sono probabilmente sbagliati).

* Ho provato a renderlo il più preciso possibile , ma a causa delle variazioni tra le macchine, potrei avere alcuni dettagli sbagliati. Tuttavia, il tuo compito è quello di implementare ciò che ho descritto, anche se sono impreciso. Non includo il plugboard per semplicità


1
Questa è un'implementazione corretta per l'algoritmo di crittografia utilizzato in Enigma I, M3 e M4. Sono presenti tutte le impostazioni, il plugboard e l'interruttore Uhr funzionano anche: https://github.com/arduinoenigma/ArduinoEnigmaEngineAndUhr Questo è lo stesso motore di crittografia utilizzato in Arduino Enigma Machine Simulator

Penso di aver capito, ma non sembra funzionare bene. Ecco un riassunto che spiega gist.github.com/JJ-Atkinson/ddd3896fe10d85b3b584 .
J Atkin,

Nel primo esempio hai detto "se stiamo usando i rotori 1, 3 e 5" ma penso che questo sarebbe rotori 1, 2 e 5 (o qualunque cosa per l'ultimo).
coredump,

@coredump Risolto
Nathan Merrill il

La mia comprensione di come funzionano i rotori è ancora errata?
J Atkin,

Risposte:


4

Python 3, 403 byte

Penso che funzioni correttamente. I rotori gli passarono:

def z(p,o,m,f,g,h):
 O=ord;b=lambda a:a[1:]+a[:1];d=lambda a:chr(a+O('A'));e=lambda a:O(a)-O('A');i=[list(g[i-1])for i in p];j=[f[i-1]for i in p];i=[x[e(y):]+x[:e(y)]for x,y in zip(i,o)];k=[]
 for l in m:
  if i[0][0]==j[0]:i[1]=b(i[1])
  elif i[1][0]==j[1]:i[1]=b(i[1]);i[2]=b(i[2])
  i[0]=b(i[0]);c=l
  for n in i:c=n[e(c)]
  c=h[e(c)]
  for n in reversed(i):c=d(n.index(c))
  k+=[c]
 return''.join(k)

fè la tacca, gè i rotori ed hè il riflettore.

Ungolfed:

shift = lambda rotor: rotor[1:] + rotor[:1]
letter = lambda num: chr(num + ord('A'))
number = lambda chr: ord(chr) - ord('A')


def encode(rotors, rotorStart, message, defaultRotors, reflector, rotorNotchPositions):
    usedRotors = [list(defaultRotors[i - 1]) for i in rotors]
    notches = [rotorNotchPositions[i - 1] for i in rotors]
    usedRotors = [rotor[number(offset):] + rotor[:number(offset)] for rotor, offset in zip(usedRotors, rotorStart)]

    sub = []

    for char in message:
        # print([''.join(rotor) for rotor in usedRotors])
        if usedRotors[0][0] == notches[0]:
            usedRotors[1] = shift(usedRotors[1])
        elif usedRotors[1][0] == notches[1]:
            usedRotors[1] = shift(usedRotors[1])
            usedRotors[2] = shift(usedRotors[2])

        usedRotors[0] = shift(usedRotors[0])

        c = char
        for rotor in usedRotors:
            c = rotor[number(c)]
        c = reflector[number(c)]
        for rotor in reversed(usedRotors):
            c = letter(rotor.index(c))
        sub += [c]
        print([''.join(rotor) for rotor in usedRotors], char, c, message)

    return ''.join(sub)

rotorNotchPositions = 'QEVJZ'
*defaultRotors, reflector = [
    #ABCDEFGHIJKLMNOPQRSTUVWXYZ#
    "EKMFLGDQVZNTOWYHXUSPAIBRCJ",  # 1
    "AJDKSIRUXBLHWTMCQGZNPYFVOE",  # 2
    "BDFHJLCPRTXVZNYEIWGAKMUSQO",  # 3
    "ESOVPZJAYQUIRHXLNFTGKDCMWB",  # 4
    "VZBRGITYUPSDNHLXAWMJQOFECK",  # 5
    "YRUHQSLDPXNGOKMIEBFZCWVJAT"   # R
]

#             Rotor       Position        Input                 Output
assert encode((4, 1, 5), ('H', 'R', 'G'), 'AAAAAAAAA',
              defaultRotors, reflector, rotorNotchPositions) == 'PXSHJMMHR'
assert encode((1, 2, 3), ('A', 'A', 'A'), 'PROGRAMMINGPUZZLES',
              defaultRotors, reflector, rotorNotchPositions) == 'RTFKHDOCCDAHRJJDFC'
assert encode((1, 2, 3), ('A', 'A', 'A'), 'RTFKHDOVZSXTRMVPFC',
              defaultRotors, reflector, rotorNotchPositions) == 'PROGRAMRXGVGUVFCES'
assert encode((2, 5, 3), ('U', 'L', 'I'), 'GIBDZNJLGXZ',
              defaultRotors, reflector, rotorNotchPositions) == 'UNCRAUPSCTK'

Penso che funzioni, ma produce un output diverso, a causa di ciò che (credo) sia un bug nell'impl di riferimento.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.