Polybius Cipher Examples & Code Implementation

Complete programming guide for Polybius Square cipher with Python and JavaScript implementations, historical examples, and educational exercises.

Quick Implementation Examples

Python Implementation

Python - Core Implementation62 lines
Highlighting code...

JavaScript Implementation

JavaScript - Modern ES660 lines
Highlighting code...

Interactive Polybius Examples

Basic Encoding: "HELLO"

beginner

Simple demonstration of Polybius Square encoding.

5x5numbers

Letter Coordinates: "CIPHER"

beginner

Using letters (A-E) instead of numbers for coordinates.

5x5letters

6x6 Grid: "CODE123"

intermediate

Extended 6x6 grid supporting both letters and digits.

6x6numbers

Basic Encoding: "HELLO"

HELLO
23 15 31 31 34
Grid:5x5
Coordinates:numbers
Difficulty:beginner

H is at row 2, column 3 (23). E is at row 1, column 5 (15). L is at row 3, column 1 (31). O is at row 3, column 4 (34).

Grid Visualization

1
2
3
4
5
1
A
B
C
D
E
2
F
G
H
I/J
merged
K
3
L
M
N
O
P
4
Q
R
S
T
U
5
V
W
X
Y
Z

Highlighted cells show character positions

Historical Examples & Applications

Ancient Greek Signals

Original Use Case: Torch signal communication across mountains

Ancient Greek Method28 lines
Highlighting code...

Telegraph Implementation

Industrial Era: Efficient numeric transmission over telegraph lines

Telegraph Era32 lines
Highlighting code...

Prison Tap Code Evolution

Vietnam War Era: POW communication through wall tapping

POW Tap Code39 lines
Highlighting code...

Pop Culture: Indiana Jones

Kingdom of the Crystal Skull: Polybius Square in modern cinema

Cinema Reference40 lines
Highlighting code...

Polybius Cipher Programming Guide & Examples

This comprehensive guide provides complete implementations of the Polybius Square cipher in multiple programming languages, along with historical examples and educational exercises to deepen your understanding of coordinate-based cryptography.

Algorithm Overview

The Polybius Square cipher converts letters into coordinate pairs based on their position in a grid. This coordinate-based approach made it ideal for long-distance communication using visual or auditory signals.

Core Concepts

Grid Structure: Letters are arranged in a square grid (typically 5×5 or 6×6) Coordinate Pairs: Each letter becomes (row, column) coordinates I/J Merger: In 5×5 grids, I and J traditionally share the same position Format Flexibility: Coordinates can be numeric (1-5) or alphabetic (A-E)

Complete Python Implementation

Basic Polybius Class

class PolybiusSquare:
    """
    Complete Polybius Square cipher implementation
    Supports both 5x5 and 6x6 grids with multiple coordinate formats
    """
    
    def __init__(self, grid_size='5x5', custom_alphabet=None):
        self.grid_size = grid_size
        self.size = 5 if grid_size == '5x5' else 6
        
        # Set alphabet based on grid size
        if custom_alphabet:
            self.alphabet = custom_alphabet.upper()
        elif grid_size == '5x5':
            # Classical: I and J merged
            self.alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'
        else:  # 6x6
            # Extended: all letters plus digits
            self.alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
        
        # Create the grid
        self.grid = self._create_grid()
        
        # Create reverse lookup for encoding
        self.char_to_pos = {}
        for row in range(self.size):
            for col in range(self.size):
                if self.grid[row][col]:
                    self.char_to_pos[self.grid[row][col]] = (row, col)
    
    def _create_grid(self):
        """Create the character grid"""
        grid = []
        for i in range(self.size):
            row = []
            for j in range(self.size):
                index = i * self.size + j
                if index < len(self.alphabet):
                    row.append(self.alphabet[index])
                else:
                    row.append('')
            grid.append(row)
        return grid
    
    def encode(self, text, coordinate_type='numeric', separator=' '):
        """
        Encode text to coordinate pairs
        
        Args:
            text: Input text to encode
            coordinate_type: 'numeric' (1-5) or 'letter' (A-E)
            separator: Character to separate coordinate pairs
        
        Returns:
            Encoded coordinate string
        """
        result = []
        
        for char in text.upper():
            # Skip non-alphabetic characters or handle specially
            if not char.isalnum():
                continue
                
            # Handle J -> I conversion for 5x5 grid
            if self.grid_size == '5x5' and char == 'J':
                char = 'I'
            
            # Get position
            if char in self.char_to_pos:
                row, col = self.char_to_pos[char]
                
                if coordinate_type == 'numeric':
                    coord = f"{row + 1}{col + 1}"
                else:  # letter
                    row_letter = chr(65 + row)  # A, B, C...
                    col_letter = chr(65 + col)
                    coord = f"{row_letter}{col_letter}"
                
                result.append(coord)
        
        return separator.join(result)
    
    def decode(self, coordinates, coordinate_type='numeric'):
        """
        Decode coordinate pairs to text
        
        Args:
            coordinates: Space-separated coordinate pairs
            coordinate_type: 'numeric' or 'letter'
        
        Returns:
            Decoded text string
        """
        # Handle different separators
        import re
        pairs = re.split(r'[\s,|\-]+', coordinates.strip())
        
        result = []
        
        for pair in pairs:
            if len(pair) == 2:
                try:
                    if coordinate_type == 'numeric':
                        row = int(pair[0]) - 1
                        col = int(pair[1]) - 1
                    else:  # letter
                        row = ord(pair[0]) - 65  # A=0, B=1...
                        col = ord(pair[1]) - 65
                    
                    # Validate coordinates
                    if (0 <= row < self.size and 0 <= col < self.size 
                        and self.grid[row][col]):
                        result.append(self.grid[row][col])
                    else:
                        result.append('?')  # Invalid coordinate
                        
                except (ValueError, IndexError):
                    result.append('?')  # Parsing error
            else:
                result.append(pair)  # Keep non-coordinate text
        
        return ''.join(result)
    
    def analyze_frequency(self, text):
        """
        Analyze character frequency in text
        Useful for educational cryptanalysis
        """
        frequency = {}
        total_chars = 0
        
        for char in text.upper():
            if char.isalpha():
                frequency[char] = frequency.get(char, 0) + 1
                total_chars += 1
        
        # Convert to percentages and sort
        freq_analysis = []
        for char, count in sorted(frequency.items(), 
                                key=lambda x: x[1], reverse=True):
            percentage = (count / total_chars) * 100
            coord = self.encode(char)
            freq_analysis.append({
                'char': char,
                'count': count,
                'percentage': round(percentage, 2),
                'coordinate': coord
            })
        
        return freq_analysis
    
    def display_grid(self):
        """Display the grid in a readable format"""
        print(f"\nPolybius Square ({self.grid_size}):")
        print("   ", end="")
        
        # Column headers
        for i in range(self.size):
            print(f" {chr(65 + i)}", end="")
        print()
        
        # Grid rows
        for i, row in enumerate(self.grid):
            print(f" {chr(65 + i)} ", end="")
            for cell in row:
                if cell:
                    print(f" {cell}", end="")
                else:
                    print("  ", end="")
            print()


# Usage Examples
def main():
    # Create 5x5 cipher
    cipher = PolybiusSquare('5x5')
    
    print("=== Polybius Square Cipher Examples ===")
    
    # Basic encoding
    message = "HELLO WORLD"
    encoded = cipher.encode(message)
    print(f"\nOriginal: {message}")
    print(f"Encoded:  {encoded}")
    
    # Decoding
    decoded = cipher.decode(encoded)
    print(f"Decoded:  {decoded}")
    
    # Different coordinate formats
    letter_coords = cipher.encode(message, 'letter')
    print(f"\nLetter coordinates: {letter_coords}")
    print(f"Decoded from letters: {cipher.decode(letter_coords, 'letter')}")
    
    # Concatenated format (no separators)
    concat_coords = cipher.encode(message, separator='')
    print(f"\nConcatenated: {concat_coords}")
    
    # Frequency analysis
    print(f"\n=== Frequency Analysis for '{message}' ===")
    freq_analysis = cipher.analyze_frequency(message)
    for item in freq_analysis:
        print(f"{item['char']}: {item['count']} times "
              f"({item['percentage']}%) - coordinate {item['coordinate']}")
    
    # Display grid
    cipher.display_grid()
    
    # 6x6 example with digits
    print(f"\n=== 6x6 Grid Example ===")
    cipher_6x6 = PolybiusSquare('6x6')
    mixed_message = "CODE123"
    encoded_6x6 = cipher_6x6.encode(mixed_message)
    print(f"Message: {mixed_message}")
    print(f"Encoded: {encoded_6x6}")
    print(f"Decoded: {cipher_6x6.decode(encoded_6x6)}")


if __name__ == "__main__":
    main()

Advanced JavaScript Implementation

/**
 * Modern JavaScript Polybius Square Implementation
 * ES6+ with advanced features and browser compatibility
 */
class PolybiusSquare {
    constructor(gridSize = '5x5', customAlphabet = null) {
        this.gridSize = gridSize;
        this.size = gridSize === '5x5' ? 5 : 6;
        
        // Set alphabet
        if (customAlphabet) {
            this.alphabet = customAlphabet.toUpperCase();
        } else if (gridSize === '5x5') {
            this.alphabet = 'ABCDEFGHIKLMNOPQRSTUVWXYZ'; // I/J merged
        } else {
            this.alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        }
        
        this.grid = this.createGrid();
        this.charToPos = this.createLookupMap();
    }
    
    createGrid() {
        const grid = [];
        for (let i = 0; i < this.size; i++) {
            const row = [];
            for (let j = 0; j < this.size; j++) {
                const index = i * this.size + j;
                row.push(this.alphabet[index] || '');
            }
            grid.push(row);
        }
        return grid;
    }
    
    createLookupMap() {
        const map = new Map();
        for (let row = 0; row < this.size; row++) {
            for (let col = 0; col < this.size; col++) {
                if (this.grid[row][col]) {
                    map.set(this.grid[row][col], { row, col });
                }
            }
        }
        return map;
    }
    
    encode(text, coordinateType = 'numeric', separator = ' ') {
        return text.toUpperCase()
            .split('')
            .filter(char => char.match(/[A-Z0-9]/))
            .map(char => {
                // Handle J -> I conversion for 5x5
                if (this.gridSize === '5x5' && char === 'J') {
                    char = 'I';
                }
                
                const pos = this.charToPos.get(char);
                if (pos) {
                    if (coordinateType === 'numeric') {
                        return `${pos.row + 1}${pos.col + 1}`;
                    } else {
                        const rowLetter = String.fromCharCode(65 + pos.row);
                        const colLetter = String.fromCharCode(65 + pos.col);
                        return `${rowLetter}${colLetter}`;
                    }
                }
                return ''; // Skip unknown characters
            })
            .filter(coord => coord.length > 0)
            .join(separator);
    }
    
    decode(coordinates, coordinateType = 'numeric') {
        // Handle various separators
        const pairs = coordinates.split(/[\s,|\-]+/).filter(pair => pair.length > 0);
        
        return pairs
            .map(pair => {
                if (pair.length === 2) {
                    let row, col;
                    
                    if (coordinateType === 'numeric') {
                        row = parseInt(pair[0]) - 1;
                        col = parseInt(pair[1]) - 1;
                    } else {
                        row = pair.charCodeAt(0) - 65;
                        col = pair.charCodeAt(1) - 65;
                    }
                    
                    if (row >= 0 && row < this.size && 
                        col >= 0 && col < this.size &&
                        this.grid[row][col]) {
                        return this.grid[row][col];
                    }
                    return '?'; // Invalid coordinate
                }
                return pair; // Keep non-coordinate text
            })
            .join('');
    }
    
    analyzeFrequency(text) {
        const frequency = new Map();
        const totalChars = text.replace(/[^A-Z]/g, '').length;
        
        for (const char of text.toUpperCase()) {
            if (char.match(/[A-Z]/)) {
                frequency.set(char, (frequency.get(char) || 0) + 1);
            }
        }
        
        return Array.from(frequency.entries())
            .map(([char, count]) => ({
                char,
                count,
                percentage: Math.round((count / totalChars) * 100 * 100) / 100,
                coordinate: this.encode(char)
            }))
            .sort((a, b) => b.count - a.count);
    }
    
    displayGrid() {
        console.log(`\nPolybius Square (${this.gridSize}):`);
        console.log('    ' + Array.from({length: this.size}, (_, i) => 
            String.fromCharCode(65 + i)).join(' '));
        
        this.grid.forEach((row, i) => {
            const rowStr = String.fromCharCode(65 + i) + ' | ' + 
                          row.map(cell => cell || ' ').join(' ');
            console.log(rowStr);
        });
    }
    
    // Utility methods for web applications
    toJSON() {
        return {
            gridSize: this.gridSize,
            alphabet: this.alphabet,
            grid: this.grid
        };
    }
    
    exportToCSV(analysis) {
        const headers = ['Character', 'Count', 'Percentage', 'Coordinate'];
        const rows = analysis.map(item => 
            [item.char, item.count, item.percentage, item.coordinate]
        );
        
        return [headers, ...rows]
            .map(row => row.join(','))
            .join('\n');
    }
}

// Browser-compatible usage examples
function demonstratePolybius() {
    console.log('=== Polybius Square JavaScript Demo ===');
    
    const cipher = new PolybiusSquare('5x5');
    
    // Basic operations
    const message = 'CRYPTOGRAPHY';
    const encoded = cipher.encode(message);
    const decoded = cipher.decode(encoded);
    
    console.log(`Original: ${message}`);
    console.log(`Encoded:  ${encoded}`);
    console.log(`Decoded:  ${decoded}`);
    
    // Frequency analysis
    const frequency = cipher.analyzeFrequency(message);
    console.log('\nFrequency Analysis:');
    frequency.forEach(item => {
        console.log(`${item.char}: ${item.count} (${item.percentage}%) → ${item.coordinate}`);
    });
    
    cipher.displayGrid();
}

// Web API integration example
class PolybiusWebAPI {
    constructor() {
        this.cipher = new PolybiusSquare();
    }
    
    async processText(text, options = {}) {
        return new Promise((resolve) => {
            setTimeout(() => {
                const result = {
                    original: text,
                    encoded: this.cipher.encode(text, options.coordinateType),
                    frequency: this.cipher.analyzeFrequency(text),
                    timestamp: new Date().toISOString()
                };
                resolve(result);
            }, 100); // Simulate async processing
        });
    }
    
    batchProcess(textArray) {
        return Promise.all(
            textArray.map(text => this.processText(text))
        );
    }
}

// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
    module.exports = { PolybiusSquare, PolybiusWebAPI };
}

Historical Examples & Applications

Ancient Greek Signal Communications

The original Polybius system used torch signals for long-distance communication:

def ancient_torch_signals():
    """
    Simulate ancient Greek torch signaling
    Each coordinate transmitted as groups of torches
    """
    
    message = "ENEMY APPROACHING"
    cipher = PolybiusSquare('5x5')
    encoded = cipher.encode(message)
    
    print("Ancient Torch Signal Protocol:")
    print(f"Message: {message}")
    print(f"Coordinates: {encoded}")
    print("\nTorch Signal Instructions:")
    
    for i, coord in enumerate(encoded.split()):
        if coord.isdigit() and len(coord) == 2:
            row, col = int(coord[0]), int(coord[1])
            print(f"Letter {i+1}: {row} torches, pause, {col} torches")

Telegraph Era Implementation

During the telegraph era, Polybius coordinates were ideal for transmission:

def telegraph_encoding():
    """
    Telegraph-optimized Polybius encoding
    Concatenated format with error detection
    """
    
    def add_checksum(encoded_text):
        """Add simple checksum for error detection"""
        checksum = sum(int(digit) for digit in encoded_text if digit.isdigit()) % 100
        return f"{encoded_text}{checksum:02d}"
    
    def verify_checksum(received_text):
        """Verify telegram integrity"""
        if len(received_text) < 2:
            return False, "Too short"
        
        message = received_text[:-2]
        expected_checksum = int(received_text[-2:])
        actual_checksum = sum(int(d) for d in message if d.isdigit()) % 100
        
        return actual_checksum == expected_checksum, message
    
    cipher = PolybiusSquare('5x5')
    message = "URGENT SUPPLIES NEEDED"
    
    # Encode without separators (telegraph style)
    encoded = cipher.encode(message, separator='')
    secured = add_checksum(encoded)
    
    print("Telegraph Transmission:")
    print(f"Original: {message}")
    print(f"Encoded: {encoded}")
    print(f"With checksum: {secured}")
    
    # Verify and decode
    is_valid, clean_message = verify_checksum(secured)
    if is_valid:
        decoded = cipher.decode(' '.join([clean_message[i:i+2] 
                                        for i in range(0, len(clean_message), 2)]))
        print(f"Decoded: {decoded}")
    else:
        print("Checksum failed - transmission error detected")

Prison Tap Code Conversion

Converting Polybius to the famous prison tap code:

def prison_tap_code():
    """
    Convert Polybius coordinates to tap code sequences
    Used by POWs for wall communication
    """
    
    def text_to_taps(text):
        cipher = PolybiusSquare('5x5')
        encoded = cipher.encode(text)
        
        tap_sequence = []
        for coord in encoded.split():
            if len(coord) == 2:
                row_taps = int(coord[0])
                col_taps = int(coord[1])
                
                # Create tap pattern
                row_pattern = '•' * row_taps
                col_pattern = '•' * col_taps
                tap_sequence.append(f"{row_pattern} | {col_pattern}")
        
        return '  '.join(tap_sequence)
    
    # Historical POW messages
    messages = [
        "GOD BLESS AMERICA",
        "STAY STRONG",
        "REMEMBER YOUR TRAINING"
    ]
    
    print("Prison Tap Code Examples:")
    for msg in messages:
        taps = text_to_taps(msg)
        print(f"\nMessage: {msg}")
        print(f"Tap code: {taps}")

Educational Exercises

Exercise 1: Frequency Analysis

Analyze the vulnerability of Polybius ciphers to frequency attacks:

def frequency_vulnerability_demo():
    """
    Demonstrate frequency analysis vulnerability
    """
    cipher = PolybiusSquare('5x5')
    
    # English text with natural letter frequencies
    sample_text = """
    THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
    THIS IS A SAMPLE TEXT FOR FREQUENCY ANALYSIS
    NOTICE HOW CERTAIN LETTERS APPEAR MORE OFTEN
    """
    
    # Encode and analyze
    encoded = cipher.encode(sample_text)
    frequency = cipher.analyze_frequency(sample_text)
    
    print("Frequency Vulnerability Analysis:")
    print(f"Sample text length: {len(sample_text.replace(' ', '').replace('\n', ''))} characters")
    print("\nTop 5 most frequent characters:")
    
    for item in frequency[:5]:
        print(f"{item['char']}: {item['count']} times ({item['percentage']}%) "
              f"→ always encoded as {item['coordinate']}")
    
    print(f"\nEncoded coordinates: {encoded}")
    print("\nSecurity note: The coordinate '44' appears frequently,")
    print("indicating the letter 'T' is common in English text.")

Exercise 2: Grid Variations

Explore different grid configurations and their implications:

def compare_grid_sizes():
    """
    Compare 5x5 vs 6x6 grid characteristics
    """
    message = "HELLO123"
    
    # 5x5 grid
    cipher_5x5 = PolybiusSquare('5x5')
    try:
        encoded_5x5 = cipher_5x5.encode(message)
        print(f"5x5 encoding: {encoded_5x5}")
    except:
        print("5x5 grid cannot encode digits")
    
    # 6x6 grid
    cipher_6x6 = PolybiusSquare('6x6')
    encoded_6x6 = cipher_6x6.encode(message)
    print(f"6x6 encoding: {encoded_6x6}")
    
    print("\nGrid Comparison:")
    print("5x5: Classical, I/J merged, letters only")
    print("6x6: Modern, all letters + digits, longer coordinates")

Exercise 3: Custom Alphabets

Experiment with custom character arrangements:

def custom_alphabet_cipher():
    """
    Create Polybius cipher with custom alphabet arrangement
    """
    # Keyword-based alphabet (remove duplicates, add remaining letters)
    keyword = "CRYPTOGRAPHY"
    remaining = "BEFHJKLMNQSUVWXZ"  # Letters not in keyword
    custom_alphabet = keyword + remaining
    
    print(f"Custom alphabet: {custom_alphabet}")
    
    cipher = PolybiusSquare('5x5', custom_alphabet)
    cipher.display_grid()
    
    message = "SECRET MESSAGE"
    encoded = cipher.encode(message)
    print(f"\nMessage: {message}")
    print(f"Encoded with custom alphabet: {encoded}")

This comprehensive guide provides the foundation for understanding and implementing Polybius Square ciphers in modern programming environments while maintaining historical accuracy and educational value.