The VIC cipher is one of the most complicated pencil and paper ciphers ever devised. Used in the 1950s by Soviet spy Reino Häyhänen, codenamed "VICTOR", its main principle is security through obfuscation; a lot of obfuscation.
Your task is to write a program or function that will take a message and encode it using the VIC cipher. I have also posted a VIC cipher decoder challenge here. If any of the following instructions are unclear, don't hesitate to ask about them in the comments. The instructions are adapted from this site.
Encoding the VIC cipher
Preparation
You will need five inputs:
- the plaintext message
- a short keyword or phrase containing the most common letters in your language
- a key phrase, such as a quote or a line from a song (at least 20 characters)
- a date (or another number that is six digits or more)
- a personal agent number
In practice, these last four should be agreed upon beforehand by the sender and the recipient, including whether the agent number of the sender or the recipient is used in encoding.
My example message will be: We are discovered. Take what you can. Burn everything else. Move to Safehouse Foxtrot 3.
We'll be encoding in English (though you may use whatever language and alphabet you prefer) and the most common letters in the English alphabet are A, E, I, N, O, R, S, T
. I'll use the keyword SENATORI
.
My key phrase is a quote by Richard Feynman: "The first principle is that you must not fool yourself — and you are the easiest person to fool."
As a date, I'll use July 31, 2016 (in the format 3172016
), which is the day it was when I wrote this description.
The personal number I have chosen for myself is 9
.
Summary of steps
- Derive the intermediate keys for use in the following steps.
- Construct and apply the straddling checkerboard.
- Construct and apply the first transposition table.
- Construct and apply the second (disrupted) transposition table.
- Finalize the message by inserting the message indicator group.
Submechanisms
Two more things to explain before we get into the meat of the matter: the processes of chain addition and sequentializing.
Chain addition, also known as a lagged Fibonacci generator, works by taking a starting digit sequence, adding the first two digits without carrying (add them together then mod 10
) and appending the result to the end. For example:
79081
7 + 9 = 6
790816
9 + 0 = 9
7908169
0 + 8 = 8
79081698
8 + 1 = 9
790816989
1 + 6 = 7
7908169897
... and so on
Sequentializing is essentially taking a sequence of letters or digits and labeling them by their alphabetical/numerical order. Duplicates are labelled left to right. For example:
E X A M P L E
0 # A
1 0 2 # Es
1 0 3 2 # L
1 0 4 3 2 # M
1 0 4 5 3 2 # P
1 6 0 4 5 3 2 # X
3 3 0 5 8 4 2 0 4 7 5 4 8 1
0 1 # 0s
0 1 2 # 1
0 3 1 2 # 2
4 5 0 3 1 2 # 3s
4 5 0 6 3 1 7 8 2 # 4s
4 5 0 9 6 3 1 7 10 8 2 # 5s
4 5 0 9 6 3 1 7 11 10 8 2 # 7
4 5 0 9 12 6 3 1 7 11 10 8 13 2 # 8s
I use zero-indexing here, but index however you like.
1. Intermediate Keys
Split the first 20 letters of the key phrase into two groups of 10 and sequentialize each individually, which we will call S1
and S2
.
THEFIRSTPR
S1: 8201357946
INCIPLEIST
S2: 2603751489
Choose a random 5-digit message identifier, M
(this can be one of the inputs if you prefer):
M = 47921
Subtract, without borrowing (subtract mod 10
), the first five digits of the key date 3172016
from M
:
M 47921
date - 31720
= 16201
Chain add the result until you have ten digits:
1620178218
Add these digits to S1
, without carrying or mod 10
, to obtain G
:
1620178218
S1 + 8201357946
G = 9821425154
Above S2
, write the sequence 0123456789. Locate each digit of G
in the sequence 0123456789 and replace it with the digit directly below it in S2
. The result is T
.
0123456789
S2 2603751489
G 9821425154
T 9806705657
Use chain addition to expand T
to 60 digits.
9806705657
becomes
980670565778637511245490262369939288595822106344304316978734
These last 50 digits, in five rows of ten digits each, form the U
block.
T 9806705657
U 7863751124
5490262369
9392885958
2210634430
4316978734
The last two non-equal digits of the U
block are individually added to the agent's personal number to give the widths of the two transpositions, p
and q
.
9 + 3 = 12 (p, first transposition width) 9 + 4 = 13 (q, second transposition width)
Sequentialize T
and use this sequence to copy off the columns of the U
block, from top to bottom, into a new row of digits, V
.
T 9806705657
seqT 9804612537
U 7863751124
5490262369
9392885958
2210634430
4316978734
V 69911 56837 12548 26533 30206 13947 72869 49804 84323 75924
Sequentialize the first p
digits to get the key for the first transposition K1
, and the following q
digits for the key for the second K2
.
First 12 6 9 9 1 1 5 6 8 3 7 1 2
K1 6 10 11 0 1 5 7 9 4 8 2 3
Next 13 5 4 8 2 6 5 3 3 3 0 2 0 6
K2 8 7 12 2 10 9 4 5 6 0 3 1 11
Finally, sequentialize the final row of the U
block to get C
, the column headers for the straddling checkerboard:
U5 4316978734
C 3105968724
2. Straddling Checkerboard
First, I will give my example checkerboard then explain the principles in creating it in that way:
3 1 0 5 9 6 8 7 2 4
S E N A T O R I
2 B D G J L P U W Y .
4 C F H K M Q V X Z #
The first line of letters is our short keyword SENATORI
. Your keyword can be any string without duplicates, but since it defines the top row of your checkerboard, choose wisely. Above the keyword is C
, and the other rows are the rest of your alphabet in whatever order you choose. In my case, I filled the checkerboard with the rest of the Latin alphabet, a punctuation mark .
and a mark for demarcating numbers #
. Essentially, the checkerboard is a fancy substitution cipher. For example, "E" will be substituted with 1
, and "W" will be substituted with 27
.
Once we have encoded our plaintext message with this checkerboard, but first, we need to make the beginning of our message less obvious by splitting it at a random position, and making it all uppercase. To denote the other original beginning, we use two full stops ..
We are discovered. Take what you can. Burn everything else. Move to Safehouse Foxtrot 3.
becomes
HING ELSE. MOVE TO SAFEHOUSE FOXTROT#3#.. WE ARE
DISCOVERED. TAKE WHAT YOU CAN. BURN EVERYT
We encode with the checkerboard, giving us:
407020 1293124 496481 96 354114062831 416479869443442424 271 581
2173436481812124 95451 274059 22628 435024 232880 14818229
If the length of the message isn't divisible by 5, we add some null characters to pad out the message. Our message is 109 digits long, so I will add one null: "4".
40702 01293 12449 64819 63541 14062 83141 64798 69443 44242 42715
81217 34364 81812 12495 45127 40592 26284 35024 23288 01481 82294
Note: Since my example message does not contain numbers, I'll say here that you might designate, say, as #3#
, which is encoded as 44344
here.
3. First Transposition
Create the transposition table by writing K1
(from the Intermediate Keys section) followed by the encoded message from the previous step, in rows of the same length, below the key:
K1 6 10 11 0 1 5 7 9 4 8 2 3
4 0 7 0 2 0 1 2 9 3 1 2
4 4 9 6 4 8 1 9 6 3 5 4
1 1 4 0 6 2 8 3 1 4 1 6
4 7 9 8 6 9 4 4 3 4 4 2
4 2 4 2 7 1 5 8 1 2 1 7
3 4 3 6 4 8 1 8 1 2 1 2
4 9 5 4 5 1 2 7 4 0 5 9
2 2 6 2 8 4 3 5 0 2 4 2
3 2 8 8 0 1 4 8 1 8 2 2
9 4
Taking the numbered columns in order of their numbers we get:
060826428 246674580 151411542 246272922 961311401 082918141
4414434239 118451234 334422028 293488758 0417249224 794943568
4. Second Transposition
The first transposition was relatively simple. This one, however, is a disrupted transposition. The disruption pattern is determined by the width of the table and the key. In our example, we have 110 digits and 13 columns, meaning we'll have 8 full rows and 6 leftovers. We start filling in the first row, but stop at column 0, and continue as follows:
K2 8 7 12 2 10 9 4 5 6 0 3 1 11
0 6 0 8 2 6 4 2 8 stop at 0
2 4 6 6 7 4 5 8 0 1 continue in a triangle pattern
5 1 4 1 1 5 4 2 2 4 6
2 7 2 9 2 2 9 6 1 3 1 1
4 0 1 0 8 2 9 1 8 1 4 1 4 until the end
4 1 4 4 3 4 2 3 9 1 1 restart and stop at 1
8 4 5 1 2 3 4 3 3 4 4 2
2 0 2 8 2 9 3 4 8 8 7 5 8
0 4 1 restart and stop at 2
Then we fill the last few spaces with the remaining digits.
K2 8 7 12 2 10 9 4 5 6 0 3 1 11
0 6 0 8 2 6 4 2 8 7 2 4 9
2 4 6 6 7 4 5 8 0 1 2 2 4
5 1 4 1 1 5 4 2 2 4 6 7 9
2 7 2 9 2 2 9 6 1 3 1 1 4
4 0 1 0 8 2 9 1 8 1 4 1 4
4 1 4 4 3 4 2 3 9 1 1 9 4
8 4 5 1 2 3 4 3 3 4 4 2 3
2 0 2 8 2 9 3 4 8 8 7 5 8
0 4 1 5 6 8
Now, we read off the columns in the exactly the same way we did for in the first transposition.
71431148 42711925 861904185 22614147 45499243 28261334 80218938
641701404 025244820 645224398 271283226 94944438 064214521
And split everything up into 5-digit groups:
71431 14842 71192 58619 04185 22614 14745 49924 32826 13348 02189
38641 70140 40252 44820 64522 43982 71283 22694 94443 80642 14521
5. Finalize the Message
The final step is to insert our random message identifier, 47921
, into the message itself. The final digit of the key date 6
indicates the distance the group should be from the end.
71431 14842 71192 58619 04185 22614 14745 49924 32826 13348 02189 38641
70140 40252 44820 64522 43982 47921 71283 22694 94443 80642 14521
Notes for this challenge
- You are given a minimum of five inputs: the message, the letter keyword, the key phrase, the date, and a personal number. You may include two additional inputs: the random message identifier and the nulls needed to pad out the message, or your function may generate some random numbers on its own.
- You may assume all inputs are valid, with the correct number of digits and letters (5-digit message identifier, at least 20 digits for the key phrase, and so on). You may assume that your strings (the message and keywords) have already had all punctuation and spaces removed except for those that you allow in your version, and that numbers are already demarcated with number signs.
- The first keyword should not have duplicate letters in it, and in your code, you may assume that it never has duplicate letters.
- The language you use to encode in does not matter, as long as the language is preexisting, the alphabet is preexisting, and you specify which language you use in your answer.
- Whichever alphabet you employ for your straddling checkerboard, you may add or remove symbols to pad the checkerboard out. Specify what you use those symbols for (for example, punctuation, a separate "message begin" symbol, symbols for common words). You may forego the number sign entirely and spell out the numbers or include each digit in the checkerboard, using the slot where the number sign was for something else. Please specify which checkerboard you used in your answer.
- The output should be either a string of space-separated five-digit groups, a list of five-digit integers, or something similar.
- I used zero-indexing and
0123456789
in my example. You may use 1-indexing and1234567890
, or some other system in your answer, as long as you specify what you used.
Here is an example implementation on Ideone.
This is a long post and I wrote most of it by hand, so if there are any confusing parts in this post or errors in my counting and transposing, please let me know. Good luck and good golfing!
adding the first two digits without adding
Do you mean carrying? \$\endgroup\$without borrowing
andwithout carrying
? Do you mean add and subtract mod10
, i.e.(6+7) mod 10 = 3
and(6-8) mod 10 = 8
? \$\endgroup\$