Merge remote-tracking branch 'origin/mk-arrows' into mk-arrows

This commit is contained in:
Mirek Kratochvil 2025-08-29 11:42:44 +02:00
commit 93ca0ce061
4 changed files with 116 additions and 106 deletions

View file

@ -2,12 +2,9 @@
// No license, but send me a hello if you use this for some good purpose. // No license, but send me a hello if you use this for some good purpose.
// -- Mirek Kratochvil <exa.exa@gmail.com> // -- Mirek Kratochvil <exa.exa@gmail.com>
//TODO: round corners? font = "FiraMono";
font = "Consolas"; //URW Bookman L looks nicely here as well alphabet = "ru";
font2 = "Droid Sans Mono";
alphabet = "en";
//inch-sized tiles look imperial. //inch-sized tiles look imperial.
tilesize=25.4; tilesize=25.4;
@ -22,11 +19,13 @@ corner=tileheight*2;
//accomodate for Ё //accomodate for Ё
if (alphabet=="ru") { if (alphabet=="ru") {
fontheight=fontheight*0.9; fontheight=fontheight*0.9;
} }
module arrow(n) { module arrow(n) {
if (n>=1) for(i=[0:n-1]) translate([i-(n-1)/2,0,0]) polygon([[0.45,0],[0,0.7],[-0.45,0]]); if (n>=1)
for(i=[0:n-1]) translate([i-(n-1)/2,0,0])
polygon([[0.45,0],[0,0.7],[-0.45,0]]);
} }
//this produces one tile //this produces one tile
@ -49,7 +48,7 @@ module tilec(letter, x, y, c) {
color("white") { color("white") {
translate([tilesize*(0.5-dx*0.13),tilesize*(0.275-dy*0.13),tileheight*.51]) translate([tilesize*(0.5-dx*0.13),tilesize*(0.275-dy*0.13),tileheight*.51])
linear_extrude (height=tileheight/2) linear_extrude (height=tileheight/2)
text(letter, font=font, size=tilesize*.45, text(letter, font=font, size=tilesize*.48,
halign="center", valign="baseline"); halign="center", valign="baseline");
} }
color("white") color("white")
@ -81,13 +80,13 @@ module tiles(letters) {
if (alphabet=="en") { if (alphabet=="en") {
// latin variant of tiles // latin variant of tiles
tiles( tiles(
["□", "A", "B", "C", "D", "E", "F", ["□", "A", "B", "C", "D", "E", "F",
"G", "H", "I", "J", "K", "L", "M", "G", "H", "I", "J", "K", "L", "M",
"N", "O", "P", "Q", "R", "S", "T", "N", "O", "P", "Q", "R", "S", "T",
"U", "V", "W", "X", "Y", "Z", ".", "U", "V", "W", "X", "Y", "Z", ".",
"/", ":", "?", "!", "'", "(", ")", ",", ":", "?", "!", "'", "(", ")",
"0", "1", "2", "3", "4", "5", "6", "0", "1", "2", "3", "4", "5", "6",
"7", "8", "9", ",", "-", "+", "*"] "7", "8", "9", "+", "-", "*", "/"]
); );
} else if (alphabet=="ru") { } else if (alphabet=="ru") {
// variant of tiles thanks to Stas Bushuev // variant of tiles thanks to Stas Bushuev

181
README.md
View file

@ -32,30 +32,30 @@ We have added some real punctuation, basic stuff for writing expressions,
punctuation and quotes. The letters of the board now look like this: punctuation and quotes. The letters of the board now look like this:
``` ```
_ a b c d e f _ A B C D E F
g h i j k l m G H I J K L M
n o p q r s t N O P Q R S T
u v w x y z . U V W X Y Z .
/ : ? ! ' ( ) , : ? ! ' ( )
0 1 2 3 4 5 6 0 1 2 3 4 5 6
7 8 9 , - + * 7 8 9 + - * /
``` ```
Zoomed in, it's very practical to have extra position information written on The cipher works with position changes. Zoomed in; it's very practical to also
the tiles: have the shift information written on the tiles as arrows:
``` ```
/-----\ /-----\ /-----\ /-----\ /-----\ .-----. .-----. .-----. .-----. .-----.
| | | | | | | | | | | | | >| | >| | >| |< |
| _ 0| | a 1| | b 2| | c 3| | d 4| ... | _ | | A | | B >| | C >| |< D | ...
| 0 | | 0 | | 0 | | 0 | | 0 | | | | | | | | >| |< |
\-----/ \-----/ \-----/ \-----/ \-----/ '-----' '-----' '-----' '-----' '-----'
/-----\ /-----\ .-----. .-----.
| | | | | | | >|
| g 0| | h 1| ... | G | | H >| ...
| 1 | | 1 | |v | |v |
\-----/ \-----/ '-----' '-----'
. . . .
. . . .
. . . .
@ -67,42 +67,43 @@ trash).
## How-To ## How-To
You may as well see the paper [1], there are also pictures. This is somewhat more concentrated: You may as well see the paper [1], there are also pictures. This is somewhat
more concentrated:
### Encryption ### Encryption
1. The symmetric key is the initial state of the board. Arrange your tiles to 7x7 square according to the key. 1. The symmetric key is the initial state of the board. Arrange your tiles to 7x7 square according to the key.
2. Put the marker on (0,0). 2. Put the marker on the tile in the upper left corner.
3. Find the next letter you want to encrypt on the board, its position is `P`. 3. Find the next letter you want to encrypt on the board (call it `P`).
4. Look at the marker; numbers written on the marked tile are coordinates `M`. 4. Look at the marker; let's call the tile under the marker `M`.
5. Compute position of the ciphertext as `C := P + M mod (7,7)`. Output the letter found on position `C` as ciphertext. 5. The marked tile `M` has arrows drawn on it. Put a finger on tile `P` and move it to next tiles according to arrows on `M` -- e.g., if it has 2 arrows to the right and one to up, you jump 2 tiles to the right and one up. In case you hit the corner of the board, do a "wraparound" and continue on the other side. After the jumps, your finger rests on the ciphertext tile; mark it `C`. This letter is now encrypted and you can "transmit" it.
6. Rotate the row that contains the plaintext letter one position to the right, but do not carry the marker if present (it should stay on the same coordinates). 6. Shift the row that contains the plaintext letter one position to the right. The tile on the right will get out of the board; so do a "wraparound" again and put it to the empty spot on the left. (Let's call this "rotation"). If the marker is present on any of the affected tiles, DO NOT CARRY IT with the tiles (it should stay on the same coordinates).
7. Rotate the column that now (after the first rotation) contains the ciphertext letter one position down, also not carrying the marker. 7. In a similar fashion, rotate the column that now (after the first rotation) contains the ciphertext tile `C` one position down, again doing the wraparound and preserving the marker position.
8. Update the position of the marker: `M := M + C' mod (7,7)` where `C'` are the numbers written on the ciphertext tile. 8. Update the position of the marker: Look at the arrow directions on the ciphertext tile `C` and move the marker according to the directions (just like previously with finding the ciphertext).
9. Repeat from 3 as many times as needed to encrypt the whole plaintext. 9. Repeat from 3 as many times as needed to encrypt the whole plaintext.
#### Encryption example with ascii images! #### Encryption example with ascii images!
``` ```
1,2. Symmetric key with 3,4. We want to encrypt 'y'. 1,2. Symmetric key with 3,4. We want to encrypt 'Y'.
marker put on 'e' Look at the marked tile: marker put on 'E': Look at the marked tile first:
[e]f _ a b c d /-----\ [E]F _ A B C D /-----\
l m g h i j k | | L M G H I J K |< |
( ) / : ? ! ' | e 5| ( ) / : ? ! ' |< E |
s t n o p q r | 0 | S T N O P Q R | |
z . u v w x y \-----/ Z . U V W X Y \-----/
5 6 0 1 2 3 4 5 6 0 1 2 3 4
+ * 7 8 9 , - + * 7 8 9 , -
5. Ciphertext is 'w' 6. Rotate the plaintext 1 position 5. Ciphertext is 'W' 6. Rotate the plaintext 1 position
(='y' moved by (5,0)) right, keep marker coordinates. (='Y' moved to <<) right, keep marker coordinates.
[e]f _ a b c d [e]f _ a b c d [E]F _ A B C D [E]F _ A B C D
Output 'w'! l m g h i j k l m g h i j k Output 'U'! L M G H I J K L M G H I J K
( ) / : ? ! ' ( ) / : ? ! ' ( ) / : ? ! ' ( ) / : ? ! '
s t n o p q r s t n o p q r S T N O P Q R S T N O P Q R
z . u v w x y >> y z . u v w x Z . U V W X Y >> Y Z . U V W X
5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4
+ * 7 8 9 , - + * 7 8 9 , - + * 7 8 9 , - + * 7 8 9 , -
@ -110,24 +111,24 @@ You may as well see the paper [1], there are also pictures. This is somewhat mor
7. Rotate the ciphertext 1 Now look at the ciphertext tile: 7. Rotate the ciphertext 1 Now look at the ciphertext tile:
position down. position down.
[e]f _ a b , d /-----\ [E]F _ A B , D /-----\
l m g h i c k | | L M G H I C K | >|
( ) / : ? j ' | w 2| ( ) / : ? J ' | W >|
s t n o p ! r | 3 | S T N O P ! R |vvv |
y z . u v q x \-----/ Y Z . U V Q X \-----/
5 6 0 1 2 w 4 5 6 0 1 2 W 4
+ * 7 8 9 3 - + * 7 8 9 3 -
8. Update the marker position 9. GOTO 3. 8. Update the marker position 9. GOTO 3.
by ciphertext offset (2,3). by ciphertext arrows (vvv>>)
e f _ a b , d E F _ A B , D
l m g h i c k L M G H I C K
( ) / : ? j ' ( ) / : ? J '
s t[n]o p ! r S T[N]O P ! R
y z . u v q x Y Z . U V Q X
5 6 0 1 2 w 4 5 6 0 1 2 W 4
+ * 7 8 9 3 - + * 7 8 9 3 -
@ -136,13 +137,13 @@ You may as well see the paper [1], there are also pictures. This is somewhat mor
### Decryption ### Decryption
Decryption procedure is basically the same, except that in step 5 you know `C` Decryption procedure is basically the same, except that in step 5 you know `C`
and `M`, and need to produce `P` by subtraction: `P := C - M mod (7,7)`. and `M`, and need to produce `P` by going back to it from `C`. Simply take the
Otherwise (except that you input ciphertext and output plaintext) everything arrows on the marked tile and use them in reverse direction starting from `C`.
stays the same.
### Key generation ### Key generation
Grab a bag full of tiles and randomly draw them one by one. Key is the 49-item permutation of them. Grab a bag full of tiles and randomly draw them one by one. Key is the 49-item
permutation of them.
## Modifications ## Modifications
@ -167,17 +168,21 @@ expand the passwords before each encryption/decryption.
The actual expansion can be as simple as this: The actual expansion can be as simple as this:
1. initialize `I:=0`, put the tiles on the board sorted by their numbers (i.e. as on the picture above) 1. Put the tiles on the board in a fixed "initial" position,
2. Take the first letter of the password and see the numbers on its tile; mark them `Px, Py`. e.g. as on the character board picture above, sorted by the arrow offsets.
3. Rotate `I`-th row `Px` positions right 2. Find the first letter of the password. Rotate it first horizontally, then
4. Rotate `I`th column `Py` positions down vertically, according to the number of arrows on the tile.
5. `I := I + 1 mod 7`, repeat from 2 with next letter of the password. 3. Find the tile below right (`v>` in arrows) of the new position of the
6. Resulting tile positions are the expanded key password letter (possibly wrapping around the board), and rotate it
horizontally and vertically according to what its arrows say -- just as with
the password letter before.
4. Repeat as needed from step 2 for the whole password.
5. Final tile positions are the expanded key.
### Undistinguishable ciphertexts ### Undistinguishable ciphertexts
To get a different ciphertext even if the same plaintext is encrypted To get a different ciphertext even if the same plaintext is encrypted
repeatedly; prepend it with a nonce. A nonce is a completely random sequence of repeatedly, prepend it with a nonce. A nonce is a completely random sequence of
letters of a pre-negotiated length (e.g. N tiles drawn randomly from a bag, letters of a pre-negotiated length (e.g. N tiles drawn randomly from a bag,
adviseable value of N is at least 10). adviseable value of N is at least 10).
@ -209,13 +214,13 @@ use of playing cards could be more innocuous and easily explainable to a
suddenly appearing adversary. Playing cards is sure less suspicious than suddenly appearing adversary. Playing cards is sure less suspicious than
playing some peculiarly numbered tiles! :] ) playing some peculiarly numbered tiles! :] )
To simplify things a bit, we will use the following layout: To simplify things a bit, we shall use the following layout:
``` ```
a b c d e f g A B C D E F G
h i j k l m n H I J K L M N
o p q r s t u O P Q R S T U
v w x y z _ . V W X Y Z _ .
, - + * / : ? , - + * / : ?
! ' ( ) 1 2 3 ! ' ( ) 1 2 3
4 5 6 7 8 9 0 4 5 6 7 8 9 0
@ -225,19 +230,19 @@ This maps nicely to the playing card suits:
| Card value | ♦ | ♣ | ♥ | ♠ | | Card value | ♦ | ♣ | ♥ | ♠ |
|------------|---|---|---|---| |------------|---|---|---|---|
| A | a | n | _ | 1 | | A | A | N | _ | 1 |
| 2 | b | o | . | 2 | | 2 | B | O | . | 2 |
| 3 | c | p | , | 3 | | 3 | C | P | , | 3 |
| 4 | d | q | - | 4 | | 4 | D | Q | - | 4 |
| 5 | e | r | + | 5 | | 5 | E | R | + | 5 |
| 6 | f | s | * | 6 | | 6 | F | S | * | 6 |
| 7 | g | t | / | 7 | | 7 | G | T | / | 7 |
| 8 | h | u | : | 8 | | 8 | H | U | : | 8 |
| 9 | i | v | ? | 9 | | 9 | I | V | ? | 9 |
| 10 | j | w | ! | 0 | | 10 | J | W | ! | 0 |
| J | k | x | ' | | | J | K | X | ' | |
| Q | l | y | ( | | | Q | L | Y | ( | |
| K | m | z | ) | | | K | M | Z | ) | |
The last 3 cards are not used. (Actually, you are free to use the suits in The last 3 cards are not used. (Actually, you are free to use the suits in
whatever order you like and discard the last 3 of the suit you like the least.) whatever order you like and discard the last 3 of the suit you like the least.)
@ -253,10 +258,10 @@ The result may look like this:
![Using cards instead of tiles](card-tiles.jpg) ![Using cards instead of tiles](card-tiles.jpg)
In this example, the marker is on J♣ (at the top left), and we want to encrypt In this example, the marker is on J♣ (at the top left), and we want to encrypt
the plaintext character `e`. The image includes the character, index, and the plaintext character `E`. The image includes the character, index, and
offsets for the relevant cards. offsets for the relevant cards.
1. From the card mapping, `e` maps to 5♦ (letters `a` through `m` map to 1. From the card mapping, `E` maps to 5♦ (letters `A` through `M` map to
Tiles), which is on the second row. Tiles), which is on the second row.
2. The marker card, J♣, has: 2. The marker card, J♣, has:
- an index of 24 (Clubs are suit 1, and the Jack is the 11th card in the - an index of 24 (Clubs are suit 1, and the Jack is the 11th card in the
@ -282,11 +287,11 @@ For the original LC4, you need just 3 suits, modifying the board to "align" to
the suits e.g. as follows: the suits e.g. as follows:
``` ```
a b c d e f A B C D E F
g h i j k l G H I J K L
m n o p q r M N O P Q R
s t u v w x S T U V W X
y z _ 2 3 4 Y Z _ 2 3 4
5 6 7 8 9 # 5 6 7 8 9 #
``` ```

2
lc4.py
View file

@ -56,7 +56,7 @@ version = "v2.8.1 (2018-07-24)"
# define alphabet # define alphabet
letters6 = "#_23456789abcdefghijklmnopqrstuvwxyz" letters6 = "#_23456789abcdefghijklmnopqrstuvwxyz"
letters6card = "abcdefghijklmnopqrstuvwxyz_23456789#" letters6card = "abcdefghijklmnopqrstuvwxyz_23456789#"
letters7 = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()" letters7 = "_abcdefghijklmnopqrstuvwxyz.,:?!'()0123456789+-*/"
letters7card = "abcdefghijklmnopqrstuvwxyz_.,-+*/:?!'()1234567890" letters7card = "abcdefghijklmnopqrstuvwxyz_.,-+*/:?!'()1234567890"

18
ls47.py
View file

@ -8,7 +8,7 @@
import random import random
letters = "_abcdefghijklmnopqrstuvwxyz.0123456789,-+*/:?!'()" letters = "_abcdefghijklmnopqrstuvwxyz.,:?!'()0123456789+-*/"
tiles = list(zip(letters, map(lambda x: (x // 7, x % 7), range(7 * 7)))) tiles = list(zip(letters, map(lambda x: (x // 7, x % 7), range(7 * 7))))
padding_size = 10 padding_size = 10
@ -85,12 +85,18 @@ def rotate_marker_down(m, col, n):
def derive_key(password): def derive_key(password):
i = 0
k = letters k = letters
for c in password: for c in password:
(row, col) = find_ix(c) (crow, ccol) = find_pos(k, c)
k = rotate_down(rotate_right(k, i, col), i, row) (rows1, cols1) = find_ix(c)
i = (i + 1) % 7 k = rotate_right(k, crow, cols1)
(crow, ccol) = add_pos((crow, ccol), (0, cols1))
k = rotate_down(k, ccol, rows1)
(crow, ccol) = add_pos((crow, ccol), (rows1+1, 1))
(rows2, cols2) = find_ix(find_at_pos(k, (crow, ccol)))
k = rotate_right(k, crow, cols2)
(crow, ccol) = add_pos((crow,ccol), (0, cols2))
k = rotate_down(k, ccol, rows2)
return k return k
@ -154,7 +160,7 @@ if __name__ == '__main__':
print(letters) print(letters)
# print('tiles positions: ' + str(tiles)) # print('tiles positions: ' + str(tiles))
key = derive_key('s3cret_p4ssw0rd/31337') key = derive_key('a')
print('test key: ' + key) print('test key: ' + key)
enc = encrypt_pad(key, 'conflagrate_the_rose_bush_at_six!', enc = encrypt_pad(key, 'conflagrate_the_rose_bush_at_six!',
'peace-vector-3') 'peace-vector-3')