Rail Fence Cipher
Definition​
- Definition
- Explanation
- Guidance
- Tips
The Rail Fence Cipher is a transposition cipher technique that rearranges the plaintext characters by writing them in a zigzag pattern across a specified number of "rails" or lines. It is a simple form of encryption that can be easily implemented
Arranging the plaintext characters in a zigzag pattern across a specified number of rails. First, the plaintext is written diagonally up and down the rails. Then, the ciphertext is formed by reading off the characters row by row
- Choose the number of rails (usually referred to as the key) for the cipher
- Write the plaintext diagonally across the rails in a zigzag pattern
- Read the characters row by row to form the ciphertext
- ensure that the number of rails chosen is less than the length of the plaintext to avoid errors
- take care when writing and reading characters diagonally to maintain the integrity of the encryption
Practice​
- Practice
- Solution
rail_fence_cipher(plaintext, num_rails):
// Initialize an empty list for each rail
rails = []
for i from 0 to num_rails - 1:
rails.append([])
// Fill the rails with the plaintext characters
rail_num = 0
direction = 1 // Direction of the diagonal movement
for char in plaintext:
rails[rail_num].append(char)
rail_num += direction
// Change direction when reaching the first or last rail
if rail_num == 0 or rail_num == num_rails - 1:
direction = -direction
// Concatenate the characters from each rail to form the ciphertext
ciphertext = ""
for rail in rails:
ciphertext += ''.join(rail)
return ciphertext
package main
import "strings"
var DIRECTIONS = map[string]int{"UP": -1, "DOWN": 1}
func buildFence(rowsNum int) [][]rune {
fence := make([][]rune, rowsNum)
for i := range fence {
fence[i] = []rune{}
}
return fence
}
func getNextDirection(railCount, currentRail, direction int) int {
if currentRail == 0 {
return DIRECTIONS["DOWN"]
} else if currentRail == railCount-1 {
return DIRECTIONS["UP"]
}
return direction
}
func fillEncodeFence(fence [][]rune, input string, railCount int) [][]rune {
currentRail := 0
direction := DIRECTIONS["DOWN"]
for _, char := range input {
fence[currentRail] = append(fence[currentRail], char)
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
}
return fence
}
func fillDecodeFence(fence [][]rune, input string, railCount int) [][]rune {
currentRail := 0
currentColumn := 0
direction := DIRECTIONS["DOWN"]
for _, char := range input {
fence[currentRail][currentColumn] = char
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
currentColumn = (currentColumn + 1) % len(input)
}
return fence
}
func decodeFence(fence [][]rune, railCount int) string {
var decodedMessage []rune
currentRail := 0
direction := DIRECTIONS["DOWN"]
for i := 0; i < railCount; i++ {
decodedMessage = append(decodedMessage, fence[currentRail]...)
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
}
return string(decodedMessage)
}
func encodeRailFenceCipher(input string, railCount int) string {
fence := buildFence(railCount)
fence = fillEncodeFence(fence, input, railCount)
var encodedMessage strings.Builder
for _, row := range fence {
for _, char := range row {
encodedMessage.WriteRune(char)
}
}
return encodedMessage.String()
}
func decodeRailFenceCipher(input string, railCount int) string {
fence := buildFence(railCount)
fence = fillDecodeFence(fence, input, railCount)
return decodeFence(fence, railCount)
}
import java.util.ArrayList;
import java.util.List;
public class RailFenceCipher {
static final int UP = -1;
static final int DOWN = 1;
static int[] buildFence(int rowsNum) {
int[] fence = new int[rowsNum];
for (int i = 0; i < rowsNum; i++) {
fence[i] = 0;
}
return fence;
}
static int getNextDirection(int railCount, int currentRail, int direction) {
if (currentRail == 0) {
return DOWN;
} else if (currentRail == railCount - 1) {
return UP;
} else {
return direction;
}
}
static int[][] fillEncodeFence(int[][] fence, String string, int railCount) {
int currentRail = 0;
int direction = DOWN;
for (char c : string.toCharArray()) {
fence[currentRail][fence[currentRail].length - 1] = c;
direction = getNextDirection(railCount, currentRail, direction);
currentRail += direction;
}
return fence;
}
static int[][] fillDecodeFence(int[][] fence, String string, int railCount) {
int currentRail = 0;
int currentColumn = 0;
int direction = DOWN;
for (char c : string.toCharArray()) {
fence[currentRail][currentColumn] = c;
direction = getNextDirection(railCount, currentRail, direction);
currentRail += direction;
currentColumn = (currentColumn + 1) % string.length();
}
return fence;
}
static String decodeFence(int[][] fence, int railCount) {
StringBuilder decodedMessage = new StringBuilder();
int currentRail = 0;
int direction = DOWN;
for (int i = 0; i < railCount; i++) {
for (int j = 0; j < fence[currentRail].length; j++) {
if (fence[currentRail][j] != 0) {
decodedMessage.append((char) fence[currentRail][j]);
}
}
direction = getNextDirection(railCount, currentRail, direction);
currentRail += direction;
}
return decodedMessage.toString();
}
public static String encodeRailFenceCipher(String string, int railCount) {
int[][] fence = new int[railCount][string.length()];
fillEncodeFence(fence, string, railCount);
StringBuilder encodedMessage = new StringBuilder();
for (int i = 0; i < railCount; i++) {
for (int j = 0; j < fence[i].length; j++) {
if (fence[i][j] != 0) {
encodedMessage.append((char) fence[i][j]);
}
}
}
return encodedMessage.toString();
}
public static String decodeRailFenceCipher(String string, int railCount) {
int[][] fence = new int[railCount][string.length()];
fillDecodeFence(fence, string, railCount);
return decodeFence(fence, railCount);
}
}
const DIRECTIONS = { UP: -1, DOWN: 1 };
const buildFence = (rowsNum) => Array.from({ length: rowsNum }, () => []);
const getNextDirection = ({ railCount, currentRail, direction }) => {
if (currentRail === 0) {
return DIRECTIONS.DOWN;
} else if (currentRail === railCount - 1) {
return DIRECTIONS.UP;
} else {
return direction;
}
};
const fillEncodeFence = (fence, string, railCount) => {
let currentRail = 0;
let direction = DIRECTIONS.DOWN;
for (const char of string) {
fence[currentRail].push(char);
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
}
return fence;
};
const fillDecodeFence = (fence, string, railCount) => {
let currentRail = 0;
let currentColumn = 0;
let direction = DIRECTIONS.DOWN;
for (const char of string) {
fence[currentRail][currentColumn] = char;
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
currentColumn = (currentColumn + 1) % string.length;
}
return fence;
};
const decodeFence = (fence, railCount) => {
const decodedMessage = [];
let currentRail = 0;
let direction = DIRECTIONS.DOWN;
for (let i = 0; i < railCount; i++) {
decodedMessage.push(...fence[currentRail]);
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
}
return decodedMessage.join("");
};
export const encodeRailFenceCipher = (string, railCount) => {
const fence = buildFence(railCount);
fillEncodeFence(fence, string, railCount);
return fence.flat().join("");
};
export const decodeRailFenceCipher = (string, railCount) => {
const fence = buildFence(railCount);
fillDecodeFence(fence, string, railCount);
return decodeFence(fence, railCount);
};
val DIRECTIONS = mapOf("UP" to -1, "DOWN" to 1)
fun buildFence(rowsNum: Int): Array<CharArray> {
return Array(rowsNum) { CharArray(0) }
}
fun getNextDirection(railCount: Int, currentRail: Int, direction: Int): Int {
return if (currentRail == 0) {
DIRECTIONS["DOWN"] ?: error("Direction not found")
} else if (currentRail == railCount - 1) {
DIRECTIONS["UP"] ?: error("Direction not found")
} else {
direction
}
}
fun fillEncodeFence(fence: Array<CharArray>, string: String, railCount: Int): Array<CharArray> {
var currentRail = 0
var direction = DIRECTIONS["DOWN"] ?: error("Direction not found")
for (char in string) {
fence[currentRail] += char
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
}
return fence
}
fun fillDecodeFence(fence: Array<CharArray>, string: String, railCount: Int): Array<CharArray> {
var currentRail = 0
var currentColumn = 0
var direction = DIRECTIONS["DOWN"] ?: error("Direction not found")
for (char in string) {
fence[currentRail][currentColumn] = char
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
currentColumn = (currentColumn + 1) % string.length
}
return fence
}
fun decodeFence(fence: Array<CharArray>, railCount: Int): String {
val decodedMessage = mutableListOf<Char>()
var currentRail = 0
var direction = DIRECTIONS["DOWN"] ?: error("Direction not found")
repeat(railCount) {
decodedMessage.addAll(fence[currentRail])
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
}
return decodedMessage.joinToString("")
}
fun encodeRailFenceCipher(string: String, railCount: Int): String {
val fence = buildFence(railCount)
fillEncodeFence(fence, string, railCount)
return fence.flatMap { it.toList() }.joinToString("")
}
fun decodeRailFenceCipher(string: String, railCount: Int): String {
val fence = buildFence(railCount)
fillDecodeFence(fence, string, railCount)
return decodeFence(fence, railCount)
}
DIRECTIONS = {"UP": -1, "DOWN": 1}
def buildFence(rowsNum):
return [[] for _ in range(rowsNum)]
def getNextDirection(railCount, currentRail, direction):
if currentRail == 0:
return DIRECTIONS["DOWN"]
elif currentRail == railCount - 1:
return DIRECTIONS["UP"]
else:
return direction
def fillEncodeFence(fence, string, railCount):
currentRail = 0
direction = DIRECTIONS["DOWN"]
for char in string:
fence[currentRail].append(char)
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
return fence
def fillDecodeFence(fence, string, railCount):
currentRail = 0
currentColumn = 0
direction = DIRECTIONS["DOWN"]
for char in string:
fence[currentRail][currentColumn] = char
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
currentColumn = (currentColumn + 1) % len(string)
return fence
def decodeFence(fence, railCount):
decodedMessage = []
currentRail = 0
direction = DIRECTIONS["DOWN"]
for _ in range(railCount):
decodedMessage.extend(fence[currentRail])
direction = getNextDirection(railCount, currentRail, direction)
currentRail += direction
return ''.join(decodedMessage)
def encodeRailFenceCipher(string, railCount):
fence = buildFence(railCount)
fillEncodeFence(fence, string, railCount)
return ''.join(''.join(row) for row in fence)
def decodeRailFenceCipher(string, railCount):
fence = buildFence(railCount)
fillDecodeFence(fence, string, railCount)
return decodeFence(fence, railCount)
use std::collections::HashMap;
const DIRECTIONS: HashMap<&str, i32> = [("UP", -1), ("DOWN", 1)]
.iter()
.cloned()
.collect();
fn build_fence(rows_num: usize) -> Vec<Vec<char>> {
vec![vec![' '; 0]; rows_num]
}
fn get_next_direction(rail_count: usize, current_rail: usize, direction: i32) -> i32 {
if current_rail == 0 {
*DIRECTIONS.get("DOWN").unwrap()
} else if current_rail == rail_count - 1 {
*DIRECTIONS.get("UP").unwrap()
} else {
direction
}
}
fn fill_encode_fence(mut fence: Vec<Vec<char>>, string: &str, rail_count: usize) -> Vec<Vec<char>> {
let mut current_rail = 0;
let mut direction = *DIRECTIONS.get("DOWN").unwrap();
for c in string.chars() {
fence[current_rail].push(c);
direction = get_next_direction(rail_count, current_rail, direction);
current_rail = (current_rail as i32 + direction) as usize;
}
fence
}
fn fill_decode_fence(mut fence: Vec<Vec<char>>, string: &str, rail_count: usize) -> Vec<Vec<char>> {
let mut current_rail = 0;
let mut current_column = 0;
let mut direction = *DIRECTIONS.get("DOWN").unwrap();
for c in string.chars() {
fence[current_rail][current_column] = c;
direction = get_next_direction(rail_count, current_rail, direction);
current_rail = (current_rail as i32 + direction) as usize;
current_column = (current_column + 1) % string.len();
}
fence
}
fn decode_fence(fence: Vec<Vec<char>>, rail_count: usize) -> String {
let mut decoded_message = Vec::new();
let mut current_rail = 0;
let mut direction = *DIRECTIONS.get("DOWN").unwrap();
for _ in 0..rail_count {
decoded_message.extend_from_slice(&fence[current_rail]);
direction = get_next_direction(rail_count, current_rail, direction);
current_rail = (current_rail as i32 + direction) as usize;
}
decoded_message.into_iter().collect()
}
pub fn encode_rail_fence_cipher(string: &str, rail_count: usize) -> String {
let fence = build_fence(rail_count);
let fence = fill_encode_fence(fence, string, rail_count);
fence.into_iter().flatten().collect()
}
pub fn decode_rail_fence_cipher(string: &str, rail_count: usize) -> String {
let fence = build_fence(rail_count);
let fence = fill_decode_fence(fence, string, rail_count);
decode_fence(fence, rail_count)
}
const DIRECTIONS: { [key: string]: number } = { UP: -1, DOWN: 1 };
const buildFence = (rowsNum: number): string[][] => {
return Array.from({ length: rowsNum }, () => []);
};
const getNextDirection = ({
railCount,
currentRail,
direction,
}: {
railCount: number;
currentRail: number;
direction: number;
}): number => {
if (currentRail === 0) {
return DIRECTIONS.DOWN;
} else if (currentRail === railCount - 1) {
return DIRECTIONS.UP;
} else {
return direction;
}
};
const fillEncodeFence = (
fence: string[][],
string: string,
railCount: number,
): string[][] => {
let currentRail = 0;
let direction = DIRECTIONS.DOWN;
for (const char of string) {
fence[currentRail].push(char);
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
}
return fence;
};
const fillDecodeFence = (
fence: string[][],
string: string,
railCount: number,
): string[][] => {
let currentRail = 0;
let currentColumn = 0;
let direction = DIRECTIONS.DOWN;
for (const char of string) {
fence[currentRail][currentColumn] = char;
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
currentColumn = (currentColumn + 1) % string.length;
}
return fence;
};
const decodeFence = (fence: string[][], railCount: number): string => {
const decodedMessage: string[] = [];
let currentRail = 0;
let direction = DIRECTIONS.DOWN;
for (let i = 0; i < railCount; i++) {
decodedMessage.push(...fence[currentRail]);
direction = getNextDirection({ railCount, currentRail, direction });
currentRail += direction;
}
return decodedMessage.join("");
};
export const encodeRailFenceCipher = (
string: string,
railCount: number,
): string => {
const fence = buildFence(railCount);
fillEncodeFence(fence, string, railCount);
return fence.flat().join("");
};
export const decodeRailFenceCipher = (
string: string,
railCount: number,
): string => {
const fence = buildFence(railCount);
fillDecodeFence(fence, string, railCount);
return decodeFence(fence, railCount);
};