Skip to content

Commit a8f0c65

Browse files
committed
Added ADFGVXCipher.java
1 parent 676d451 commit a8f0c65

File tree

1 file changed

+130
-0
lines changed

1 file changed

+130
-0
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import java.util.Arrays;
4+
import java.util.HashMap;
5+
import java.util.Map;
6+
/**
7+
* The ADFGVX cipher is a historically significant cipher used by
8+
* the German Army during World War I. It is a fractionating transposition
9+
* cipher that combines a Polybius square substitution with a columnar
10+
* transposition. It's named after the six letters (A, D, F, G, V, X)
11+
* that it uses in its substitution process.
12+
* https://en.wikipedia.org/wiki/ADFGVX_cipher
13+
*
14+
* @author bennybebo
15+
*/
16+
public class ADFGVXCipher {
17+
18+
private static final char[] POLYBIUS_LETTERS = {'A', 'D', 'F', 'G', 'V', 'X'};
19+
private static final char[][] POLYBIUS_SQUARE = {
20+
{'P', 'H', '0', 'Q', 'G', '6'},
21+
{'4', 'M', 'E', 'A', '1', 'Y'},
22+
{'L', '2', 'N', 'O', 'F', 'D'},
23+
{'X', 'K', 'R', '3', 'C', 'V'},
24+
{'S', '5', 'Z', 'W', '7', 'B'},
25+
{'J', '9', 'U', 'T', 'I', '8'}
26+
};
27+
private static final Map<String, Character> POLYBIUS_MAP = new HashMap<>();
28+
private static final Map<Character, String> REVERSE_POLYBIUS_MAP = new HashMap<>();
29+
30+
static {
31+
for (int i = 0; i < POLYBIUS_SQUARE.length; i++) {
32+
for (int j = 0; j < POLYBIUS_SQUARE[i].length; j++) {
33+
String key = "" + POLYBIUS_LETTERS[i] + POLYBIUS_LETTERS[j];
34+
POLYBIUS_MAP.put(key, POLYBIUS_SQUARE[i][j]);
35+
REVERSE_POLYBIUS_MAP.put(POLYBIUS_SQUARE[i][j], key);
36+
}
37+
}
38+
}
39+
40+
// Encrypts the plaintext using the ADFGVX cipher
41+
public String encrypt(String plaintext, String key) {
42+
plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", "");
43+
StringBuilder fractionatedText = new StringBuilder();
44+
45+
// Step 1: Polybius square substitution
46+
for (char c : plaintext.toCharArray()) {
47+
fractionatedText.append(REVERSE_POLYBIUS_MAP.get(c));
48+
}
49+
50+
// Step 2: Columnar transposition
51+
return columnarTransposition(fractionatedText.toString(), key);
52+
}
53+
54+
// Decrypts the ciphertext using the ADFGVX cipher
55+
public String decrypt(String ciphertext, String key) {
56+
// Step 1: Reverse the columnar transposition
57+
String fractionatedText = reverseColumnarTransposition(ciphertext, key);
58+
59+
// Step 2: Polybius square substitution
60+
StringBuilder plaintext = new StringBuilder();
61+
for (int i = 0; i < fractionatedText.length(); i += 2) {
62+
String pair = fractionatedText.substring(i, i + 2);
63+
plaintext.append(POLYBIUS_MAP.get(pair));
64+
}
65+
66+
return plaintext.toString();
67+
}
68+
69+
private String columnarTransposition(String text, String key) {
70+
int numRows = (int) Math.ceil((double) text.length() / key.length());
71+
char[][] table = new char[numRows][key.length()];
72+
for (char[] row : table) {
73+
Arrays.fill(row, '_'); // Fill with underscores to handle empty cells
74+
}
75+
76+
// Fill the table row by row
77+
for (int i = 0; i < text.length(); i++) {
78+
table[i / key.length()][i % key.length()] = text.charAt(i);
79+
}
80+
81+
// Read columns based on the alphabetical order of the key
82+
StringBuilder ciphertext = new StringBuilder();
83+
char[] sortedKey = key.toCharArray();
84+
Arrays.sort(sortedKey);
85+
86+
for (char keyChar : sortedKey) {
87+
int column = key.indexOf(keyChar);
88+
for (char[] row : table) {
89+
if (row[column] != '_') {
90+
ciphertext.append(row[column]);
91+
}
92+
}
93+
}
94+
95+
return ciphertext.toString();
96+
}
97+
98+
private String reverseColumnarTransposition(String ciphertext, String key) {
99+
int numRows = (int) Math.ceil((double) ciphertext.length() / key.length());
100+
char[][] table = new char[numRows][key.length()];
101+
102+
char[] sortedKey = key.toCharArray();
103+
Arrays.sort(sortedKey);
104+
105+
int index = 0;
106+
// Fill the table column by column according to the sorted key order
107+
for (char keyChar : sortedKey) {
108+
int column = key.indexOf(keyChar);
109+
for (int row = 0; row < numRows; row++) {
110+
if (index < ciphertext.length()) {
111+
table[row][column] = ciphertext.charAt(index++);
112+
} else {
113+
table[row][column] = '_'; // Fill empty cells with an underscore
114+
}
115+
}
116+
}
117+
118+
// Read the table row by row to get the fractionated text
119+
StringBuilder fractionatedText = new StringBuilder();
120+
for (char[] row : table) {
121+
for (char cell : row) {
122+
if (cell != '_') {
123+
fractionatedText.append(cell);
124+
}
125+
}
126+
}
127+
128+
return fractionatedText.toString();
129+
}
130+
}

0 commit comments

Comments
 (0)