Skip to content

Add main, test for Rail Fence Cipher and update README.md #5757

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 12 commits into from
4 changes: 4 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
* [AES](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AES.java)
* [AESEncryption](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AESEncryption.java)
* [AffineCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AffineCipher.java)
* [AtbashCipher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java)
* [Autokey](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Autokey.java)
* [Blowfish](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Blowfish.java)
* [Caesar](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/ciphers/Caesar.java)
Expand All @@ -59,6 +60,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)
Expand Down Expand Up @@ -663,6 +665,7 @@
* [LFSRTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/LFSRTest.java)
* [AESEncryptionTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AESEncryptionTest.java)
* [AffineCipherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java)
* [AtbashTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AtbashTest.java)
* [AutokeyTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/AutokeyTest.java)
* [BlowfishTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/BlowfishTest.java)
* [CaesarTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/CaesarTest.java)
Expand All @@ -671,6 +674,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)
Expand Down
71 changes: 71 additions & 0 deletions src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package com.thealgorithms.ciphers;

/**
* The Atbash cipher is a simple substitution cipher that replaces each letter
* in the alphabet with its reverse.
* For example, 'A' becomes 'Z', 'B' becomes 'Y', and so on. It works
* identically for both uppercase and lowercase letters.
* It's a symmetric cipher, meaning applying it twice returns the original text.
* Hence, the encrypting and the decrypting functions are identical
* @author https://github.com/Krounosity
* Learn more: https://en.wikipedia.org/wiki/Atbash
*/

public class AtbashCipher {

private String toConvert;

// Default constructor.
AtbashCipher() {
}

// String setting constructor.
AtbashCipher(String str) {
toConvert = str;
}

// String getter method.
public String getString() {
return toConvert;
}

// String setter method.
public void setString(String str) {
toConvert = str;
}

// Checking whether the current character is capital.
private boolean isCapital(char ch) {
return ch >= 'A' && ch <= 'Z';
}

// Checking whether the current character is smallcased.
private boolean isSmall(char ch) {
return ch >= 'a' && ch <= 'z';
}

// Converting text to atbash cipher code or vice versa.
public String convert() {

// Using StringBuilder to store new string.
StringBuilder convertedString = new StringBuilder();

// Iterating for each character.
for (char ch : toConvert.toCharArray()) {

// If the character is smallcased.
if (isSmall(ch)) {
convertedString.append((char) ('z' - (ch - 'a')));
}
// If the character is capital cased.
else if (isCapital(ch)) {
convertedString.append((char) ('Z' - (ch - 'A')));
}
// Non-alphabetical character.
else {
convertedString.append(ch);
}
}
return convertedString.toString();
}
}
129 changes: 129 additions & 0 deletions src/main/java/com/thealgorithms/ciphers/RailFenceCipher.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
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();
}
}
28 changes: 28 additions & 0 deletions src/test/java/com/thealgorithms/ciphers/AtbashTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.thealgorithms.ciphers;

import static org.junit.jupiter.api.Assertions.assertEquals;

import org.junit.jupiter.api.Test;

public class AtbashTest {

@Test
public void atbashEncrypt() {
AtbashCipher normalToEncrypt = new AtbashCipher("Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!");
String expectedText = "Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!";

normalToEncrypt.setString(normalToEncrypt.convert());

assertEquals(expectedText, normalToEncrypt.getString());
}

@Test
public void atbashDecrypt() {
AtbashCipher encryptToNormal = new AtbashCipher("Svool Dliow! 123, @xrksvi zyxWVU ABC 987 nzwzn aaA Kzormwilnv!");
String expectedText = "Hello World! 123, @cipher abcDEF ZYX 987 madam zzZ Palindrome!";

encryptToNormal.setString(encryptToNormal.convert());

assertEquals(expectedText, encryptToNormal.getString());
}
}
62 changes: 62 additions & 0 deletions src/test/java/com/thealgorithms/ciphers/RailFenceTest.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
Loading