This program implements a Vigenère cipher, supporting both encipherment and decipherment of text messages using a user-supplied keyword. It pre-computes a 26×26 substitution table stored in array A, where each row represents a Caesar-shifted alphabet corresponding to a keyword letter. The encoding relies on character codes offset by 37, which aligns with the ZX81’s character set where uppercase ‘A’ is code 38. Decipherment performs a linear search across each row of the array to reverse the substitution, rather than computing it algebraically. The program switches between FAST and SLOW modes to balance display speed during computation and user interaction.
Program Analysis
Program Structure
The program is divided into four logical phases:
- Initialisation (lines 40–130): Builds a 26×26 Vigenère substitution table in array
Ausing FAST mode. - User Input (lines 150–280): Prompts for a keyword (
K$), a message (M$), and an operation choice (Q$) in SLOW mode. - Encipherment (lines 330–430): Iterates over the message, cycling through the keyword, and prints each enciphered character.
- Decipherment (lines 450–560): Iterates over the message and searches each row of
Afor the matching cipher value, printing the plaintext character.
Lines 570–580 are a SAVE/RUN footer used for tape storage and auto-restart.
The Vigenère Table
The array A(26,26) is populated at lines 70–130. Row I contains the alphabet shifted left by I-1 positions, achieved by initialising J=-1 before the outer loop and incrementing it each iteration. The wrap-around at line 110 (IF A(I,K)>26 THEN LET A(I,K)=A(I,K)-26) keeps values in the range 1–26.
Character Code Arithmetic
All character lookups subtract 37 from the ZX81 character code. On the ZX81, uppercase letters run from code 38 (‘A’) to 63 (‘Z’), so subtracting 37 maps ‘A’→1 through ‘Z’→26, aligning neatly with the 1-based array indices. The reverse operation, CHR$(value + 37), reconstructs the printable letter.
Encipherment Logic
Lines 360–430 use a manual loop rather than a FOR…NEXT construct. The counter T indexes into the message, while S cycles through the keyword with modular arithmetic at line 390. The enciphered character is produced at line 410:
PRINT CHR$ (37 + A(CODE K$(S)-37, CODE M$(T)-37))
This looks up row = keyword-letter index, column = message-letter index in the pre-built table, which is the standard Vigenère substitution.
Decipherment Logic
Decipherment at lines 490–550 uses a FOR X=1 TO 26 linear search across each row of A, testing whether A(keyword-row, X) = cipher-letter index. When the match is found, CHR$(X+37) is printed. While functionally correct, this is O(26) per character rather than a direct inverse calculation, and it will print the character for every matching cell (though in a valid Vigenère row each value appears exactly once, so this is safe in practice).
Control Flow and Notable Idioms
- Line 310 (
IF Q$<>"E" OR Q$<>"D" THEN GOTO 260) is a logic bug: due to the use ofOR, this condition is always true (any string is not equal to at least one of the two literals), so it always re-prompts regardless of valid input. In practice this line is only reached when neither line 290 nor 300 branched, so it works correctly by coincidence — the branch at 310 is redundant but harmless. - Line 320 is missing from the listing; line 330 is the actual start of the encipherment block. The
GOTO 320at line 290 targets line 330, which is the next available line — a common ZX81 idiom whereGO TOto a non-existent line falls through to the next. - Line 420 branches to line 140, which does not exist; execution falls through to line 150, restarting the input prompts after encipherment — another deliberate use of the non-existent-line technique.
- Similarly, line 560
GOTO 140restarts the program loop after decipherment. FAST/SLOWswitching is used appropriately: computation in FAST mode, display and input in SLOW mode.
Limitations
- The program handles only uppercase letters (codes 38–63). Any other character in the keyword or message will produce incorrect character code arithmetic and likely a program error.
- No validation is performed on the keyword or message contents.
- Spaces and punctuation in
M$will cause out-of-range array accesses.
Content
Source Code
10 REM "CYPHER"
40 FAST
50 DIM A(26,26)
60 LET J=-1
70 FOR I=1 TO 26
80 LET J=J+1
90 FOR K=1 TO 26
100 LET A(I,K)=K+J
110 IF A(I,K)>26 THEN LET A(I,K)=A(I,K)-26
120 NEXT K
130 NEXT I
150 PRINT
160 PRINT
170 SLOW
180 PRINT " ENTER KEYWORD"
190 INPUT K$
200 PRINT K$
210 PRINT
220 PRINT " ENTER MESSAGE"
230 INPUT M$
240 PRINT M$
250 PRINT
260 PRINT " ENCYPHER/DECYPHER? (ENTER E OR D)"
270 INPUT Q$
280 PRINT
290 IF Q$="E" THEN GOTO 320
300 IF Q$="D" THEN GOTO 440
310 IF Q$<>"E" OR Q$<>"D" THEN GOTO 260
330 FAST
340 PRINT " ENCYPHERED MESSAGE READS:-"
350 PRINT
360 LET S=0
370 LET T=0
380 LET S=S+1
390 IF S>LEN K$ THEN LET S=S-LEN K$
400 LET T=T+1
410 PRINT CHR$ (37+A(CODE K$(S)-37,CODE M$(T)-37));
420 IF T=LEN M$ THEN GOTO 140
430 GOTO 380
450 FAST
460 LET Z=0
470 PRINT " DECYPHERED MESSAGE READS:-"
480 PRINT
490 FOR W=1 TO LEN M$
500 LET Z=Z+1
510 IF Z>LEN K$ THEN LET Z=Z-LEN K$
520 FOR X=1 TO 26
530 IF A(CODE K$(Z)-37,X)=CODE M$(W)-37 THEN PRINT CHR$ (X+37);
540 NEXT X
550 NEXT W
560 GOTO 140
570 SAVE "1017%7"
580 RUN
Note: Type-in program listings on this website use ZMAKEBAS notation for graphics characters.
