ThatSoftwareDude
Developer Tools, Guides and Articles

Menu

Implementing the Rail Fence Cipher in JavaScript

Implementing the Rail Fence Cipher in JavaScript

The Rail Fence Cipher is one of the simplest ciphers in the realm of cryptography. But it's the most visually interesting encryption methods as well. Unlike substitution ciphers that replace letters, the rail fence cipher works by rearranging letters in a specific zig zag pattern.

How It Works

Let's take a look at how it works. The rail fence cipher writes your messages in a zigzag pattern (which is why it's also called the Zig Zag Cipher) on a number of "rails" (like a fence), then reads the message off row by row. For example, with 3 rails, the message "HELLO WORLD" would be written as:

H . . . O . . . L . .
. E . L . W . R . D .
. . L . . . O . . . .

The first letter starts at the top left corner and works its way downward moving to the left on each iteration.

Reading off each row gives us: "HOLELWRDLO", which is our encrypted string. But if you read it from top to bottom (in a Zig Zag fashion) you'll see the 'Hello World'.

That's the heart of the cipher, and once you see it, you really can't unsee it. Here is a quick JavaScript implementation that you can test out.

JavaScript Implementation

Let's implement both encryption and decryption functions:

function encrypt(text, rails) {
    // Remove spaces and convert to uppercase for consistency
    text = text.replace(/\s/g, '').toUpperCase();
    
    // Create the rail fence array
    let fence = [];
    for (let i = 0; i < rails; i++) {
        let row = [];
        for (let j = 0; j < text.length; j++) {
            row.push('');
        }
        fence.push(row);
    }

The array holding the created 'fence' will resemble the following after being generated:

[
    ['', '', '', '', ''],  // First rail
    ['', '', '', '', ''],  // Second rail
    ['', '', '', '', '']   // Third rail
]

The length of each array will be the length of the string you are trying to encrypt.

Next up, we're going to iterate through each character in the string and add it to the appropriate slot in its specific rail.

    let rail = 0;
    let direction = 1;  // 1 for moving down, -1 for moving up
    
    // Place characters in zigzag pattern
    for (let i = 0; i < text.length; i++) {
        fence[rail][i] = text[i];
        
        // Change direction if we hit the top or bottom rail
        if (rail === 0) direction = 1;
        if (rail === rails - 1) direction = -1;
        
        rail += direction;
    }
    
    // Read off the fence row by row
    return fence.map(row => row.join('')).join('');
}

Overall, encryption is pretty straightforward. You're essentially moving downward (or upward) down a 2D array and adding each letter in your original string accordingly. At the end we collapse all of the rails row by row into one giant string.

Decryption

Decryption of a Rail Fence cipher is a bit trickier than encryption and will require a bit more code and explanation. To simplify the process, we'll be be breaking down decryption into various helper functions.

Create a fence

// First, let's create a fence using the number of rails required
function createEmptyFence(rails, length) {
    let fence = [];
    for (let i = 0; i < rails; i++) {
        // Create each rail as an array filled with empty strings
        let rail = [];
        for (let j = 0; j < length; j++) {
            rail.push('');
        }
        fence.push(rail);
    }
    return fence;
}

And once again, this will generate a pattern like this:

[
    ['', '', '', '', ''],  // First rail
    ['', '', '', '', ''],  // Second rail
    ['', '', '', '', '']   // Third rail
]

Make a fence pattern

Next up we're going to run down the 2D array from top left corner downwards (and upwards) towards the right, and we're going to add an asterisk in these specific locations.

These are the locations that will end up storing a letter from our encrypted string.

function markFencePattern(rails, length) {
    let fence = createEmptyFence(rails, length);
    
    let currentRail = 0;          // Start at the top rail
    let goingDown = true;         // Start moving downward
    
    // Walk through each position in the text
    for (let i = 0; i < length; i++) {
        // Mark this position with an asterisk
        fence[currentRail][i] = '*';
        
        // Time to change direction?
        if (currentRail === 0) {                  // At top rail
            goingDown = true;                     // Start going down
        } else if (currentRail === rails - 1) {   // At bottom rail
            goingDown = false;                    // Start going up
        }
        
        // Move to next rail
        if (goingDown) {
            currentRail++;    // Move down one rail
        } else {
            currentRail--;    // Move up one rail
        }
    }
    
    return fence;
}

This function will generate a pattern like the following:

Rail 0:  *       *       *      
Rail 1:    *   *   *   *   *    
Rail 2:      *       *          

Fill the fence

Now that we have the pattern, it's time to start to sequentially add each letter of the encrypted string in place of the asterisks.

// Fill in the fence with our encrypted text
function fillFence(fence, encryptedText) {
    let textIndex = 0;
    
    // Go rail by rail
    for (let rail = 0; rail < fence.length; rail++) {
        // Go through each position in this rail
        for (let pos = 0; pos < fence[rail].length; pos++) {
            // If there's an asterisk here, put the next letter
            if (fence[rail][pos] === '*') {
                fence[rail][pos] = encryptedText[textIndex];
                textIndex++;
            }
        }
    }
    
    return fence;
}

The fill fence function simply has to locate these asterisks and (in order) add the encrypted letters in those fields.

Read the zig zag pattern

Now that we have recreated the Zig Zag pattern using the encrypted characters, all we have to do is read them in order in order to get our final word.

// Read off the text in zigzag pattern
function readZigZag(fence) {
    let message = '';
    let currentRail = 0;
    let goingDown = true;
    
    // Walk through each position
    for (let i = 0; i < fence[0].length; i++) {
        // Add the letter from current position
        message += fence[currentRail][i];
        
        // Time to change direction?
        if (currentRail === 0) {
            goingDown = true;
        } else if (currentRail === fence.length - 1) {
            goingDown = false;
        }
        
        // Move to next rail
        if (goingDown) {
            currentRail++;
        } else {
            currentRail--;
        }
    }
    
    return message;
}

Decrypt

Now putting it all together we have the following final function:

function decrypt(encryptedText, rails) {
    // Step 1: Create the pattern of where letters should go
    let fence = markFencePattern(rails, encryptedText.length);
    
    // Step 2: Fill in the pattern with our encrypted letters
    fence = fillFence(fence, encryptedText);
    
    // Step 3: Read off the letters in zigzag pattern
    return readZigZag(fence);
}

Usage Example

// Example usage
const message = "HELLO WORLD";
const railCount = 3;

const encrypted = encrypt(message, railCount);
console.log("Encrypted:", encrypted);  // Outputs: "HORELWOLLD"

const decrypted = decrypt(encrypted, railCount);
console.log("Decrypted:", decrypted);  // Outputs: "HELLOWORLD"

How the Code Works

  1. Encryption Process:

    • Creates a 2D array representing the fence
    • Places characters in a zigzag pattern
    • Reads off the result row by row
  2. Decryption Process:

    • Creates the fence structure with placeholder characters
    • Fills in the cipher text row by row
    • Reads off the result in a zigzag pattern

Breaking the Cipher

The rail fence cipher is relatively weak by modern standards. It can be broken by:

  • Trying different rail counts (brute force)
  • Looking for patterns in letter frequency
  • Using the fact that certain letter combinations are more common in English

Again, these ciphers are great for practicing your coding skills and for understanding how cryptography has evolved throughout the centuries.

But they definitely should not be used to encrypt any sensitive information that you may be working with.

Having said that, it's one of my favorite ciphers. It looks cool when you get the visual of how the characters are laid out, and the decryption process is pretty clever.

Walter G. author of blog post
Walter Guevara is a Computer Scientist, software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20 years.

Get the latest programming news directly in your inbox!

Have a question on this article?

You can leave me a question on this particular article (or any other really).

Ask a question

Community Comments

No comments posted yet

Add a comment