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.
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
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"
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
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);
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 |
Many ciphers use alphabets, for example:
var cipher = new Rot13Cipher(alphabet);
And many other tools, like 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.
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
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"
A Polybius Square is a set of characters ordered into a square matrix. It is used by many ciphers, for example Playfair.
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
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
}
You can convert it to a character array:
char[,] array = polybiusSquare.ToCharArray();
Warning: ToCharArray
allocates a new array for each call
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);
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.
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.
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.
Use the following constants for special values:
Name | Description |
---|---|
EmptyValue |
Empty cell in the top row. |
FullStop |
The . character. |
NumericEscape |
The / character. |
You can convert it to a character array:
char[,] array = checkerboard.ToCharArray();
Warning: ToCharArray
allocates a new array for each call
The library follows the layout of arrays determined by the .NET specifications. Which means that two-dimensional arrays are indexed as follows:
- row index
- 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.