Add Rail Fence Cipher (#5761)

This commit is contained in:
Varnan Rathod
2024-10-15 20:53:10 +05:30
committed by GitHub
parent 3e10f8f1d8
commit b35f98a67a
3 changed files with 211 additions and 0 deletions

View File

@ -73,6 +73,7 @@
* [PlayfairCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
* [Polybius](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Polybius.java)
* [ProductCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/ProductCipher.java)
* [RailFenceCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java)
* [RSA](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/RSA.java)
* [SimpleSubCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/SimpleSubCipher.java)
* [Vigenere](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Vigenere.java)
@ -729,6 +730,7 @@
* [HillCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/HillCipherTest.java)
* [PlayfairTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PlayfairTest.java)
* [PolybiusTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/PolybiusTest.java)
* [RailFenceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RailFenceTest.java)
* [RSATest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/RSATest.java)
* [SimpleSubCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/SimpleSubCipherTest.java)
* [VigenereTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/VigenereTest.java)

View File

@ -0,0 +1,147 @@
package com.thealgorithms.ciphers;
import java.util.Arrays;
/**
* The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher.
* It derives its name from the manner in which encryption is performed, in analogy to a fence built with horizontal rails.
* https://en.wikipedia.org/wiki/Rail_fence_cipher
* @author https://github.com/Krounosity
*/
public class RailFenceCipher {
// Encrypts the input string using the rail fence cipher method with the given number of rails.
public String encrypt(String str, int rails) {
// Base case of single rail or rails are more than the number of characters in the string
if (rails == 1 || rails >= str.length()) {
return str;
}
// Boolean flag to determine if the movement is downward or upward in the rail matrix.
boolean down = true;
// Create a 2D array to represent the rails (rows) and the length of the string (columns).
char[][] strRail = new char[rails][str.length()];
// Initialize all positions in the rail matrix with a placeholder character ('\n').
for (int i = 0; i < rails; i++) {
Arrays.fill(strRail[i], '\n');
}
int row = 0; // Start at the first row
int col = 0; // Start at the first column
int i = 0;
// Fill the rail matrix with characters from the string based on the rail pattern.
while (col < str.length()) {
// Change direction to down when at the first row.
if (row == 0) {
down = true;
}
// Change direction to up when at the last row.
else if (row == rails - 1) {
down = false;
}
// Place the character in the current position of the rail matrix.
strRail[row][col] = str.charAt(i);
col++; // Move to the next column.
// Move to the next row based on the direction.
if (down) {
row++;
} else {
row--;
}
i++;
}
// Construct the encrypted string by reading characters row by row.
StringBuilder encryptedString = new StringBuilder();
for (char[] chRow : strRail) {
for (char ch : chRow) {
if (ch != '\n') {
encryptedString.append(ch);
}
}
}
return encryptedString.toString();
}
// Decrypts the input string using the rail fence cipher method with the given number of rails.
public String decrypt(String str, int rails) {
// Base case of single rail or rails are more than the number of characters in the string
if (rails == 1 || rails >= str.length()) {
return str;
}
// Boolean flag to determine if the movement is downward or upward in the rail matrix.
boolean down = true;
// Create a 2D array to represent the rails (rows) and the length of the string (columns).
char[][] strRail = new char[rails][str.length()];
int row = 0; // Start at the first row
int col = 0; // Start at the first column
// Mark the pattern on the rail matrix using '*'.
while (col < str.length()) {
// Change direction to down when at the first row.
if (row == 0) {
down = true;
}
// Change direction to up when at the last row.
else if (row == rails - 1) {
down = false;
}
// Mark the current position in the rail matrix.
strRail[row][col] = '*';
col++; // Move to the next column.
// Move to the next row based on the direction.
if (down) {
row++;
} else {
row--;
}
}
int index = 0; // Index to track characters from the input string.
// Fill the rail matrix with characters from the input string based on the marked pattern.
for (int i = 0; i < rails; i++) {
for (int j = 0; j < str.length(); j++) {
if (strRail[i][j] == '*') {
strRail[i][j] = str.charAt(index++);
}
}
}
// Construct the decrypted string by following the zigzag pattern.
StringBuilder decryptedString = new StringBuilder();
row = 0; // Reset to the first row
col = 0; // Reset to the first column
while (col < str.length()) {
// Change direction to down when at the first row.
if (row == 0) {
down = true;
}
// Change direction to up when at the last row.
else if (row == rails - 1) {
down = false;
}
// Append the character from the rail matrix to the decrypted string.
decryptedString.append(strRail[row][col]);
col++; // Move to the next column.
// Move to the next row based on the direction.
if (down) {
row++;
} else {
row--;
}
}
return decryptedString.toString();
}
}

View File

@ -0,0 +1,62 @@
package com.thealgorithms.ciphers;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class RailFenceTest {
@Test
void testEncryption() {
RailFenceCipher cipher = new RailFenceCipher();
String input = "We are discovered! Flee at once";
int rails = 3;
String encrypted = cipher.encrypt(input, rails);
assertEquals("Wrivdlaneaedsoee!Fe toc cr e e", encrypted);
String singleChar = "A";
int singleRail = 2;
String encryptedSingleChar = cipher.encrypt(singleChar, singleRail);
assertEquals("A", encryptedSingleChar);
String shortString = "Hello";
int moreRails = 10;
String encryptedShortString = cipher.encrypt(shortString, moreRails);
assertEquals("Hello", encryptedShortString);
String inputSingleRail = "Single line";
int singleRailOnly = 1;
String encryptedSingleRail = cipher.encrypt(inputSingleRail, singleRailOnly);
assertEquals("Single line", encryptedSingleRail);
}
@Test
void testDecryption() {
RailFenceCipher cipher = new RailFenceCipher();
// Scenario 1: Basic decryption with multiple rails
String encryptedInput = "Wrivdlaneaedsoee!Fe toc cr e e";
int rails = 3;
String decrypted = cipher.decrypt(encryptedInput, rails);
assertEquals("We are discovered! Flee at once", decrypted);
// Scenario 2: Single character string decryption
String encryptedSingleChar = "A";
int singleRail = 2; // More than 1 rail
String decryptedSingleChar = cipher.decrypt(encryptedSingleChar, singleRail);
assertEquals("A", decryptedSingleChar);
// Scenario 3: String length less than the number of rails
String encryptedShortString = "Hello";
int moreRails = 10; // More rails than characters
String decryptedShortString = cipher.decrypt(encryptedShortString, moreRails);
assertEquals("Hello", decryptedShortString);
// Scenario 4: Single rail decryption (output should be the same as input)
String encryptedSingleRail = "Single line";
int singleRailOnly = 1;
String decryptedSingleRail = cipher.decrypt(encryptedSingleRail, singleRailOnly);
assertEquals("Single line", decryptedSingleRail);
}
}