DOTSIESCIPHERGEN

A C++ toolkit for encryption and analysis using the Dotsies font's 5-bit alphabet

Where it came from

DotsiesCipherGen Console Interface

My friend Robie showed me the Dotsies typeface sometime in undergrad. He has a passing interest in linguistics and I guess some of it rubbed off. Dotsies is an alternative alphabet where each letter is encoded as a vertical column of five dots — present or absent — which means every letter is just a 5-bit pattern.

The thing that hooked me is that 5 bits gives you 32 possible values, and the English alphabet only has 26 letters. You have enough room for the full grapheme set plus punctuation, all packed into a bitset. As soon as I thought about it that way, the cipher angle was obvious — if every letter is a number, you can do arithmetic on text. Shift bits, swap columns, rotate rows. Standard substitution ciphers but operating directly on the binary representation of the alphabet rather than a lookup table.

So I built a C++ framework to play with that: encoding text into Dotsies patterns, applying transformations, and then trying to work backwards from ciphertext using frequency analysis.

Architecture

The framework is split into a handful of focused components:

Component Purpose Key Features
letter.h/cpp 5-bit pattern representation Bit manipulation, circular shifts, pattern analysis
ciphertext.h/cpp Text container and transformations Row/column operations, batch processing, bounds checking
table.h/cpp Character mapping system Letter-to-pattern mapping, custom alphabets
parser.h/cpp Text parsing and conversion String-to-ciphertext conversion, validation
decrypter.h/cpp Cryptographic analysis Frequency analysis, pattern matching, optimization algorithms

There are multiple build targets depending on what you need — the full ncurses interactive version, a text-only build for systems without ncurses, a standalone decrypter demo, and some matrix operation examples. The Makefile handles all of it:

Makefile Configuration Makefile
# Compilation flags
CFLAGS = -g -Wall -O3 -march=native -std=c++11

# Feature flags
-DNO_NCURSES    # Disable ncurses for text-only builds
-DNDEBUG        # Disable debug assertions for release builds

Usage

Basic letter operations

C++ Letter Class Usage C++
// Create a letter with specific bit pattern
letter l(std::bitset<5>("10101"));

// Perform circular shift
l.circle_shift(true, 2);  // Shift right by 2 positions

// Check bit values
bool bit3 = l.get(3);
l.set(2, true);

// Print pattern
l.printb();  // Outputs: "# # #"

Text encryption

C++ Text Encryption C++
// Create ciphertext from string
table t;  // Default alphabet mapping
parser ps(t);
ciphertext ct = ciphertext::from_string("hello world", t);

// Apply transformations
ct.row_shift(1, true, 2);    // Shift row 1 right by 2
ct.column_swap(0, 4);        // Swap columns 0 and 4
ct.column_shift(true, 1);    // Rotate all columns right by 1

Decryption analysis

C++ Decryption Analysis C++
// Initialize decrypter with dictionary
decrypter dec(ps, "dictionary.txt");

// Analyze encrypted text
dec.analyze(encrypted_ct);

// Get best decryption attempt
std::string result = dec.best_guess(encrypted_ct);

// Advanced decryption with optimization
auto result = dec.advanced_decrypt(encrypted_ct, 50);

Sample output

Terminal Output Output
=== DotsiesCipherGen Decrypter Demo ===
1. Encrypt a custom message
2. Use a sample message
3. Decrypt an existing ciphertext
4. Exit

Ciphertext information:
Length: 43 letters
Bit patterns:
Letter 0: 10101
Letter 1: 11010
Letter 2: 01101
...

===== Results Comparison =====
Original: the quick brown fox jumps over the lazy dog
Decrypted: the quick brown fox jumps over the lazy dog
Character match: 43/43 (100.00%)
Decryption SUCCESS!

Technical notes

The decryption side was the most interesting problem. Since the cipher space is small (5 bits per letter), brute force is tractable for short messages, but for anything longer you need a smarter approach. The decrypter uses English letter frequency matching as a starting point, then n-gram analysis to score candidate decryptions, with simulated annealing to escape local optima. It's not novel cryptanalysis — these are standard techniques — but applying them to a bit-manipulation cipher rather than a traditional substitution cipher was a fun constraint to work within.

Algorithm complexity at a glance:

  • Letter operations — O(1) for bit manipulations
  • Text transformations — O(n) where n is text length
  • Decryption — O(kⁿ) naive, brought down significantly with frequency analysis + annealing

The build uses C++11 throughout — std::bitset for the patterns, std::unique_ptr where ownership is clear, move semantics to avoid unnecessary copies on the larger ciphertext objects. Bounds checking is gated behind NDEBUG so debug builds are safe and release builds are fast.