M-209 Workings - Computer view


M-209 Home Page
M-209 Workings Home Page M-209 Workings:

Introduction

The following program emulates the operation of a M-209. It is written in Python. There are few comments, but his logic translates the mechanical or mathematical operations already studied.

The Program

 
# m209.py

def letter2number( letter ):
    return "ABCDEFGHIJKLMNOPQRSTUVWXYZ".find( letter )

def number2letter( number ):
    return "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[ number ]

def external2Number( wheel, letter ):
    return Wheels[ wheel ].find( letter )

def number2External( wheel, number ):
    return Wheels[ wheel ][ number % len( Wheels[wheel] ) ]

def cipherOrDecipher( letter ):
    # 1. Convert Plain letter to Plain index
    P = letter2number( letter )
    if DEBUG: print "%1s %2d " % (letter, P),

    # 2. Calculate Key
    K = 0
    for aBar in range( len(Lugs) ):
        aBarShifted = False
        for aWheel in range(len(Wheels)):
            if Pins[aWheel][ activePins[aWheel] % len(Pins[aWheel]) ] * Lugs[aBar][aWheel] :
                aBarShifted = True
        if aBarShifted :
            K = K + 1
    if DEBUG:
        for aWheel in range(len(Wheels)):
            print Pins[aWheel][ activePins[aWheel] % len(Pins[aWheel]) ],

    # 3. Cipher (or Decipher)
    C = (25 + K) - P
    C = C % 26

    # 4. Convert Cipher index to Cipher letter
    letter = number2letter( C )
    if DEBUG: print " %2d %2d " % (K, C),
    return letter

def cipherOrDecipherBis( letter ):
    # 1. Convert Plain letter to Plain index
    P = letter2number( letter )
    if DEBUG: print "%1s %2d " % (letter, P),

    # 2. Calculate Overlaps
    Overlaps = 0
    for x in sorted( LugsXY.keys() ):
        indx1 = int( x[0] )
        indx2 = int( x[1] )
        if Pins[indx1][ activePins[indx1]%len(Pins[indx1])] *  \
           Pins[indx2][ activePins[indx2]%len(Pins[indx2])]:
              Overlaps += LugsXY[ x ]
    if DEBUG:
        for aWheel in range(len(Wheels)):
            print Pins[aWheel][ activePins[aWheel] % len(Pins[aWheel]) ],

    # 3. Calculate Key
    K = 0
    for aWheel in range(len(Wheels)):
        K = K + Pins[aWheel][activePins[aWheel] % len(Pins[aWheel]) ]*LugsByWheel[aWheel]
    K = K - Overlaps

    # 4. Cipher (or Decipher)
    C = (25 + K) - P
    C = C % 26

    # 5. Convert Cipher index to Cipher letter
    letter = number2letter( C )
    if DEBUG: print " %2d %2d %2d " % (K,Overlaps,C),
    return letter

def bars2lugsAndOverlaps():
    for aWheel in range(len(Wheels)):
        LugsByWheel[ aWheel ] = 0
    numberOfOverlaps = 0
    for aBar in range(27):
        nbLugs = 0
        for aWheel in range(len(Wheels)):
            if Lugs[aBar][aWheel]:
                LugsByWheel[aWheel] = LugsByWheel[aWheel] + 1
                nbLugs = nbLugs + 1
        if nbLugs > 1:
            numberOfOverlaps = numberOfOverlaps + 1
            ndx = ""
            for aWheel in range(len(Wheels)):
                if Lugs[aBar][aWheel]: ndx = ndx + str(aWheel)
            if ndx in LugsXY:
                LugsXY[ ndx ] = LugsXY[ ndx ] + 1
            else:
                LugsXY[ ndx ] = 1

# Internal Key (from TM 11-380, 1944)
Pins = [
 [1,1,0,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,1,1,0,1,1,0,0,0],
 [1,0,0,1,1,0,1,0,0,1,1,1,0,0,1,0,0,1,1,0,1,0,1,0,0],
 [1,1,0,0,0,0,1,1,0,1,0,1,1,1,0,0,0,1,1,1,1,0,1],
 [0,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,0,0,1,1,1],
 [0,1,0,1,1,1,0,1,1,0,0,0,1,1,0,1,0,0,1],
 [1,1,0,1,0,0,0,1,0,0,1,0,0,1,1,0,1]
]

Lugs = [
  [0,0,1,0,0,1], [0,1,0,0,0,0], [0,1,0,0,0,0],
  [0,0,0,0,0,1], [0,1,0,0,0,0], [0,1,0,0,1,0],
  [1,0,0,0,0,1], [0,1,0,0,0,0], [0,1,0,0,1,0],
  [1,0,0,0,1,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
  [0,0,0,1,1,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
  [0,0,0,1,0,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
  [0,0,0,1,0,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
  [0,0,0,1,0,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
  [0,0,0,1,0,0], [0,1,0,0,0,0], [0,0,0,0,1,0],
]

Wheels = [
   "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
   "ABCDEFGHIJKLMNOPQRSTUVXYZ",
   "ABCDEFGHIJKLMNOPQRSTUVX",
   "ABCDEFGHIJKLMNOPQRSTU",
   "ABCDEFGHIJKLMNOPQRS",
   "ABCDEFGHIJKLMNOPQ"
]

LugsByWheel = [ 0, 0, 0, 0, 0, 0 ]
LugsXY = {}

External2Internal = [ 15, 14, 13, 12, 11, 10 ]

activePins = [ 0, 0, 0, 0, 0, 0 ]

ExternalKey = "PEOPLE"

DEBUG=True
Plain_text = "ATTACKZATZDAWN"
Cipher_text = ""

# activePins
for aWheel in range(len(Wheels)):
    activePins[aWheel] = External2Internal[aWheel] + external2Number( aWheel, ExternalKey[aWheel] )

# Cipher a text
for letter in Plain_text:
    if DEBUG:
        for aWheel in range(len(Wheels)):
            print number2External( aWheel, (activePins[aWheel] - External2Internal[aWheel]) % 
                len(Wheels[aWheel] ) ),
        print " : ",
    result = cipherOrDecipher( letter )
    print result,
    if DEBUG: print
    Cipher_text = Cipher_text + result
    for aWheel in range(len(Wheels)):
        activePins[aWheel] = activePins[aWheel] + 1
print
if DEBUG:
    for aWheel in range(len(Wheels)):
        print number2External( aWheel, (activePins[aWheel] - External2Internal[aWheel]) %
            len(Wheels[aWheel] ) ),
print

# Convert Lugs in LugsByWheel and Overlaps
bars2lugsAndOverlaps()
print LugsByWheel
print LugsXY
print

# Decipher a text
for aWheel in range(len(Wheels)):
    activePins[aWheel] = External2Internal[aWheel] + external2Number( aWheel, ExternalKey[aWheel] )
for letter in Cipher_text:
    if DEBUG:
	for aWheel in range(len(Wheels)):
            print number2External( aWheel, activePins[aWheel] ),
        print " : ",
    result = cipherOrDecipherBis( letter )
    print result,
    if DEBUG: print
    for aWheel in range(len(Wheels)):
        activePins[aWheel] = activePins[aWheel] + 1
print

Execution

C:\> python m209.py
P E O P L E  :  A  0  0 1 0 0 1 1  23 22  W
Q F P Q M F  :  T 19  0 0 0 1 1 0  14 20  U
R G Q R N G  :  T 19  0 1 1 1 1 1  27  7  H
S H R S O H  :  A  0  1 0 1 0 0 1   4  3  D
T I S T P I  :  C  2  1 1 0 0 1 1  23 20  U
U J T U Q J  :  K 10  0 0 1 0 1 0  11  0  A
V K U A R K  :  Z 25  1 0 0 1 0 1   9  9  J
W L V B S L  :  A  0  0 1 1 1 0 0  18 17  R
X M X C A M  :  T 19  1 0 1 0 0 0   3  9  J
Y N A D B N  :  Z 25  1 0 1 1 1 0  16 16  Q
Z O B E C O  :  D  3  0 1 0 0 1 1  23 19  T
A P C F D P  :  A  0  0 1 0 0 0 0  12 11  L
B Q D G E Q  :  W 22  0 0 0 1 1 0  14 17  R
C R E H F A  :  N 13  0 1 1 1 0 1  20  6  G

D S F I G B
[2, 12, 1, 5, 10, 3]
{'25': 1, '34': 1, '14': 2, '04': 1, '05': 1}

E S E G D O  :  W 22  0 1 0 0 1 1  23  2  0  A
F T F H E P  :  U 20  0 0 0 1 1 0  14  1 19  T
G U G I F Q  :  H  7  0 1 1 1 1 1  27  4 19  T
H V H J G A  :  D  3  1 0 1 0 0 1   4  2  0  A
I X I K H B  :  U 20  1 1 0 0 1 1  23  4  2  C
J Y J L I C  :  A  0  0 0 1 0 1 0  11  0 10  K
K Z K M J D  :  J  9  1 0 0 1 0 1   9  1 25  Z
L A L N K E  :  R 17  0 1 1 1 0 0  18  0  0  A
M B M O L F  :  J  9  1 0 1 0 0 0   3  0 19  T
N C N P M G  :  Q 16  1 0 1 1 1 0  16  2 25  Z
O D O Q N H  :  T 19  0 1 0 0 1 1  23  2  3  D
P E P R O I  :  L 11  0 1 0 0 0 0  12  0  0  A
Q F Q S P J  :  R 17  0 0 0 1 1 0  14  1 22  W
R G R T Q K  :  G  6  0 1 1 1 0 1  20  1 13  N