mirror of
https://github.com/TheAlgorithms/Java.git
synced 2025-07-07 01:35:16 +08:00
Add Rail Fence Cipher (#5761)
This commit is contained in:
@ -73,6 +73,7 @@
|
|||||||
* [PlayfairCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/PlayfairCipher.java)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [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)
|
* [VigenereTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/VigenereTest.java)
|
||||||
|
147
src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
Normal file
147
src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
62
src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
Normal file
62
src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user