Skip to content

Latest commit

 

History

History
372 lines (307 loc) · 11.3 KB

File metadata and controls

372 lines (307 loc) · 11.3 KB

Basics

Alphabet

An alphabet is the most primitive building block of almost all cryptography operations. An alphabet is an ordered list of letters, which usually determines the domain of the encryption.

Create an alphabet

You can create one by simplfy specifiying the exact characters:

var alphabet = new Alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ");

Or reorder letters by a keyword:

var english = new Alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
var key = Alphabet.FromKeyword("EXAMPLE", english); // "EXAMPLBCDFGHIJKNOQRSTUVWYZ"

The number of characters can be found in Length:

int count = alphabet.Length; // 26

Access characters in an alphabet

Note: indexing starts from 0.

Simply index the alphabet:

char thirdLetter = alphabet[2]; // 'C'

Index either from the start or its end:

char lastLetter = alphabet[^1]; // 'Z'

Or get a range:

ReadOnlySpan<char> fromSecondToFourth = alphabet[1..5]; // "BCD"

Operations

You can access characters by indexing:

char thirdLetter = alphabet[2]; // 'C'

But many ciphers need arithmetic operations which can under- or overflow, so alphabet provides AtMod for convenient out of bound access:

char nextSecondLetter = alphabet.AtMod(27); // 'B'
char lastLetter = alphabet.AtMod(-1); // 'Z'

Note: all other indexing operations throw an ArgumentOutOfRangeException in case of overflow.

Check whether a character is in the alphabet:

bool containsG = alphabet.Contains('G'); // true
bool containsg = alphabet.Contains('g', StringComparison.OrdinalIgnoreCase); // true

bool containsOmega = alphabet.Contains('Ω'); // false

Find the index of a character in the alphabet:

int indexOfE = alphabet.IndexOf('E'); // 4
int indexOfe = alphabet.IndexOf('e', StringComparison.OrdinalIgnoreCase); // 4
int indexOfEOre = alphabet.IndexOfIgnoreCase('E'); // 4

Extract its content

You can access it as a string:

string str = alphabet.ToString();

You can convert it to a character array:

char[] array = alphabet.ToCharArray();

Warning: ToCharArray allocates a new array for each call

If you want to spare memory allocation, you can either read the alphabet as a span:

ReadOnlySpan<char> characters = alphabet.AsSpan();

Or copy its content to a preallocated buffer:

char[] buffer;
alphabet.CopyTo(buffer);

Well known alphabets

There are a couple of useful alphabets built in, which can be access from the WellKnownAlphabets class:

var english = WellKnownAlphabets.English;

List of built-in alphabets:

Name Letters
English ABCDEFGHIJKLMNOPQRSTUVWXYZ
EnglishWithoutI ABCDEFGHJKLMNOPQRSTUVWXYZ
EnglishWithoutJ ABCDEFGHIKLMNOPQRSTUVWXYZ
EnglishWithoutK ABCDEFGHIJLMNOPQRSTUVWXYZ
EnglishWithoutL ABCDEFGHIJKMNOPQRSTUVWXYZ
EnglishWithoutQ ABCDEFGHIJKLMNOPRSTUVWXYZ

Use an alphabet

Many ciphers use alphabets, for example:

var cipher = new Rot13Cipher(alphabet);

And many other tools, like Tabula Recta.

Tabula Recta

The tabula recta is a square table of alphabets, each row of which is made by shifting the previous one to the left (see Wikipedia). For example, it is used by Vigenère.

Create a tabula recta

You can create a TabulaRecta from an Alphabet:

var tabula = new TabulaRecta(WellKnownAlphabets.English);

Which would look like this:

  | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
--+----------------------------------------------------
A | A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
B | B C D E F G H I J K L M N O P Q R S T U V W X Y Z A
C | C D E F G H I J K L M N O P Q R S T U V W X Y Z A B
D | D E F G H I J K L M N O P Q R S T U V W X Y Z A B C
E | E F G H I J K L M N O P Q R S T U V W X Y Z A B C D
F | F G H I J K L M N O P Q R S T U V W X Y Z A B C D E
G | G H I J K L M N O P Q R S T U V W X Y Z A B C D E F
H | H I J K L M N O P Q R S T U V W X Y Z A B C D E F G
I | I J K L M N O P Q R S T U V W X Y Z A B C D E F G H
J | J K L M N O P Q R S T U V W X Y Z A B C D E F G H I
K | K L M N O P Q R S T U V W X Y Z A B C D E F G H I J
L | L M N O P Q R S T U V W X Y Z A B C D E F G H I J K
M | M N O P Q R S T U V W X Y Z A B C D E F G H I J K L
N | N O P Q R S T U V W X Y Z A B C D E F G H I J K L M
O | O P Q R S T U V W X Y Z A B C D E F G H I J K L M N
P | P Q R S T U V W X Y Z A B C D E F G H I J K L M N O
Q | Q R S T U V W X Y Z A B C D E F G H I J K L M N O P
R | R S T U V W X Y Z A B C D E F G H I J K L M N O P Q
S | S T U V W X Y Z A B C D E F G H I J K L M N O P Q R
T | T U V W X Y Z A B C D E F G H I J K L M N O P Q R S
U | U V W X Y Z A B C D E F G H I J K L M N O P Q R S T
V | V W X Y Z A B C D E F G H I J K L M N O P Q R S T U
W | W X Y Z A B C D E F G H I J K L M N O P Q R S T U V
X | X Y Z A B C D E F G H I J K L M N O P Q R S T U V W
Y | Y Z A B C D E F G H I J K L M N O P Q R S T U V W X
Z | Z A B C D E F G H I J K L M N O P Q R S T U V W X Y

Using the tabula recta

You can find intersecting characters by simply indexing it. All operations can be indexed by both numbers or characters.

char intersection = tabulaRecta['D', 'B']; // 'E'
char intersection = tabulaRecta[3, 1]; // 'E'

You can also extract a whole row or column:

string thirdRow = tabulaRecta.GetRowOrColumn('C'); // "CDEFGHIJKLMNOPQRSTUVWXYZAB"
string thirdRow = tabulaRecta.GetRowOrColumn(2); // "CDEFGHIJKLMNOPQRSTUVWXYZAB"

Warning: instance method GetRowOrColumn a new string. And a backing storage array string[] as well to cache rows, so all subsequent calls can be allocation free.

To avoid memory allocation, all operations are available as static methods, for example:

char[] buffer;
TabulaRecta.GetRowOrColumn(alphabet, 'C', buffer); // "CDEFGHIJKLMNOPQRSTUVWXYZAB"

Polybius Square

A Polybius Square is a set of characters ordered into a square matrix. It is used by many ciphers, for example Playfair.

Create a polybius square

You can simply create one by specifying the exact characters (or an alphabet):

var polybiusSquare = PolybiusSquare.FromCharacters("ABCDEFGHJKLMNOPQRSTUVWXYZ");

Which would result in this:

A B C D E
F G H I K
L M N O P
Q R S T U
V W X Y Z

Or by a keyword:

var polybiusSquare = PolybiusSquare.FromKeyword("PLAYFAIREXAMPLE", WellKnownAlphabets.EnglishWithoutJ);

Which would result in this:

P L A Y F
I R E X M
B C D G H
K N O Q S
T U V W Z

Once created you can get its size:

int size = polybiusSquare.Size; // 5

Operations

Important! Instead of [x, y] indexing order, use [row, column], see Layout of two-dimensional arrays for more information.

Reference for examples:

P L A Y F
I R E X M
B C D G H
K N O Q S
T U V W Z

You can get characters from it by indexing:

char secondRowThirdColumn = polybiusSquare[1, 2]; // E
char secondRowThirdColumn = polybiusSquare[(1, 2)]; // E

You can test for whether it contains a specific character or not:

bool containsI = polybiusSquare.Contains('I'); // true
bool containsJ = polybiusSquare.Contains('J'); // false

You can find the position of an exact character:

if (polybiusSquare.TryFindOffsets('I', out (int row, int column) position)
{
	// found
}

Extract its content

You can convert it to a character array:

char[,] array = polybiusSquare.ToCharArray();

Warning: ToCharArray allocates a new array for each call

Use a polybius square

Many ciphers use it as a key for example:

var playfair = new PlayfairCipher();
var key = PolybiusSquare.FromKeyword("PLAYFAIREXAMPLE", WellKnownAlphabets.EnglishWithoutJ);
var plaintext = "sample";
var ciphertext = playfair.Encrypt(plaintext, key);

Straddling Checkerboard

A straddling checkerboard is a device for converting an alphanumeric plaintext into digits whilst simultaneously achieving fractionation (a simple form of information diffusion) and data compression relative to other schemes using digits.

Create a Straddling Checkerboard

var checkerboard = StraddlingCheckerboard.Create(new char[,]
{
	{ 'E', 'T', '\0', 'A', 'O', 'N', '\0', 'R', 'I', 'S' }, // (empty)
	{ 'B', 'C', 'D',  'F', 'G', 'H', 'J',  'K', 'L', 'M' }, // 2
	{ 'P', 'Q', '/',  'U', 'V', 'W', 'X',  'Y', 'Z', '.' }, // 6
}, 2, 6);

Note: for empty cells and special values, use constants available on StraddlingCheckerboard. The example code was intentionally shortened.

Operations

You can access the elements by indexing the instance in row-column order. Rows can be referenced by the chose indexes, not by numerical order. For columns, indexing starts from zero.

var C = checkerboard[2, 1]; // 'C'
var U = checkerboard[6, 3]; // 'U'

Use StraddlingCheckerboard.EmptyIndex to index the top row:

var A = checkerboard[StraddlingCheckerboard.EmptyIndex, 3]; // 'A'

You can also find the position of an exact character:

if (checkerboard.TryFindOffsets('Z', out (int row, int column) position)
{
	// found (row: 6, column: 8)
}

Note: row indexes are translated are not in numerical order.

Special values

Use the following constants for special values:

Name Description
EmptyValue Empty cell in the top row.
FullStop The . character.
NumericEscape The / character.

Extract its content

You can convert it to a character array:

char[,] array = checkerboard.ToCharArray();

Warning: ToCharArray allocates a new array for each call

Arrays

Layout of two-dimensional arrays

The library follows the layout of arrays determined by the .NET specifications. Which means that two-dimensional arrays are indexed as follows:

  1. row index
  2. column index

For example, the array:

|   | 0 | 1 | 2 |
|---+---+---+---|
| 0 | C | I | P |
|---+---+---+---|
| 1 | H | E | R |

has 2 rows and 3 columns, and is indexed as follows:

example[0, 0] = 'C';
example[0, 1] = 'I';
example[0, 2] = 'P';
example[1, 0] = 'H';
example[1, 1] = 'E';
example[1, 2] = 'R';

Its raw memory representation looks like this (2x3 = 6 length):

| 0 | 1 | 2 | 3 | 4 | 5 |
|---+---+---+---+---+---|
| C | I | P | H | E | R |

The reason the library follows the .NET layout and not the mathematical one (x, y), is to be able to compatible, so a two-dimensional array can be flatten out, to be able to use vectorization techniques (search, copy, etc...).

For example, the ArrayHelper class contains lots of utilities to manage arrays. One of them is FillFast which basically works like this:

char[,] buffer = new char[5, 5];
Span<char> flat = MemoryMarshal.CreateSpan(ref buffer[0, 0], length: 25);
alphabet.AsSpan().CopyTo(flat);

So we get this:

A B C D E
F G H I K
L M N O P
Q R S T U
V W X Y Z

And as you can see, the implementation doesn't contain two embedded loops for indexing, it works on the multi-dimensional array as a flat structure, and takes advantages of vectorized operations.