Skip to content

Commit 393337f

Browse files
authored
Add Tests for HillCipher (TheAlgorithms#5562)
1 parent 389d1d7 commit 393337f

File tree

2 files changed

+105
-144
lines changed

2 files changed

+105
-144
lines changed
Lines changed: 69 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -1,178 +1,103 @@
11
package com.thealgorithms.ciphers;
22

3-
import java.util.Scanner;
3+
public class HillCipher {
44

5-
/*
6-
* Java Implementation of Hill Cipher
7-
* Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number
8-
* belonging to the set Z26 where A=0 , B=1, ..... Z=25. To encrypt a message, each block of n
9-
* letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against
10-
* modulus 26. To decrypt the message, each block is multiplied by the inverse of the matrix used
11-
* for encryption. The cipher key and plaintext/ciphertext are user inputs.
12-
* @author Ojasva Jain
13-
*/
14-
public final class HillCipher {
15-
private HillCipher() {
16-
}
17-
18-
static Scanner userInput = new Scanner(System.in);
19-
20-
/* Following function encrypts the message
21-
*/
22-
static void encrypt(String message) {
23-
message = message.toUpperCase();
24-
// Get key matrix
25-
System.out.println("Enter key matrix size");
26-
int matrixSize = userInput.nextInt();
27-
System.out.println("Enter Key/encryptionKey matrix ");
28-
int[][] keyMatrix = new int[matrixSize][matrixSize];
29-
for (int i = 0; i < matrixSize; i++) {
30-
for (int j = 0; j < matrixSize; j++) {
31-
keyMatrix[i][j] = userInput.nextInt();
32-
}
33-
}
34-
// check if det = 0
5+
// Encrypts the message using the key matrix
6+
public String encrypt(String message, int[][] keyMatrix) {
7+
message = message.toUpperCase().replaceAll("[^A-Z]", "");
8+
int matrixSize = keyMatrix.length;
359
validateDeterminant(keyMatrix, matrixSize);
3610

37-
int[][] messageVector = new int[matrixSize][1];
38-
String cipherText = "";
39-
int[][] cipherMatrix = new int[matrixSize][1];
40-
int j = 0;
41-
while (j < message.length()) {
11+
StringBuilder cipherText = new StringBuilder();
12+
int[] messageVector = new int[matrixSize];
13+
int[] cipherVector = new int[matrixSize];
14+
int index = 0;
15+
16+
while (index < message.length()) {
4217
for (int i = 0; i < matrixSize; i++) {
43-
if (j >= message.length()) {
44-
messageVector[i][0] = 23;
18+
if (index < message.length()) {
19+
messageVector[i] = message.charAt(index++) - 'A';
4520
} else {
46-
messageVector[i][0] = (message.charAt(j)) % 65;
21+
messageVector[i] = 'X' - 'A'; // Padding with 'X' if needed
4722
}
48-
System.out.println(messageVector[i][0]);
49-
j++;
5023
}
51-
int x;
52-
int i;
53-
for (i = 0; i < matrixSize; i++) {
54-
cipherMatrix[i][0] = 0;
5524

56-
for (x = 0; x < matrixSize; x++) {
57-
cipherMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
25+
for (int i = 0; i < matrixSize; i++) {
26+
cipherVector[i] = 0;
27+
for (int j = 0; j < matrixSize; j++) {
28+
cipherVector[i] += keyMatrix[i][j] * messageVector[j];
5829
}
59-
System.out.println(cipherMatrix[i][0]);
60-
cipherMatrix[i][0] = cipherMatrix[i][0] % 26;
61-
}
62-
for (i = 0; i < matrixSize; i++) {
63-
cipherText += (char) (cipherMatrix[i][0] + 65);
30+
cipherVector[i] = cipherVector[i] % 26;
31+
cipherText.append((char) (cipherVector[i] + 'A'));
6432
}
6533
}
66-
System.out.println("Ciphertext: " + cipherText);
34+
35+
return cipherText.toString();
6736
}
6837

69-
// Following function decrypts a message
70-
static void decrypt(String message) {
71-
message = message.toUpperCase();
72-
// Get key matrix
73-
System.out.println("Enter key matrix size");
74-
int n = userInput.nextInt();
75-
System.out.println("Enter inverseKey/decryptionKey matrix ");
76-
int[][] keyMatrix = new int[n][n];
77-
for (int i = 0; i < n; i++) {
78-
for (int j = 0; j < n; j++) {
79-
keyMatrix[i][j] = userInput.nextInt();
80-
}
81-
}
82-
// check if det = 0
83-
validateDeterminant(keyMatrix, n);
38+
// Decrypts the message using the inverse key matrix
39+
public String decrypt(String message, int[][] inverseKeyMatrix) {
40+
message = message.toUpperCase().replaceAll("[^A-Z]", "");
41+
int matrixSize = inverseKeyMatrix.length;
42+
validateDeterminant(inverseKeyMatrix, matrixSize);
43+
44+
StringBuilder plainText = new StringBuilder();
45+
int[] messageVector = new int[matrixSize];
46+
int[] plainVector = new int[matrixSize];
47+
int index = 0;
8448

85-
// solving for the required plaintext message
86-
int[][] messageVector = new int[n][1];
87-
String plainText = "";
88-
int[][] plainMatrix = new int[n][1];
89-
int j = 0;
90-
while (j < message.length()) {
91-
for (int i = 0; i < n; i++) {
92-
if (j >= message.length()) {
93-
messageVector[i][0] = 23;
49+
while (index < message.length()) {
50+
for (int i = 0; i < matrixSize; i++) {
51+
if (index < message.length()) {
52+
messageVector[i] = message.charAt(index++) - 'A';
9453
} else {
95-
messageVector[i][0] = (message.charAt(j)) % 65;
54+
messageVector[i] = 'X' - 'A'; // Padding with 'X' if needed
9655
}
97-
System.out.println(messageVector[i][0]);
98-
j++;
9956
}
100-
int x;
101-
int i;
102-
for (i = 0; i < n; i++) {
103-
plainMatrix[i][0] = 0;
10457

105-
for (x = 0; x < n; x++) {
106-
plainMatrix[i][0] += keyMatrix[i][x] * messageVector[x][0];
58+
for (int i = 0; i < matrixSize; i++) {
59+
plainVector[i] = 0;
60+
for (int j = 0; j < matrixSize; j++) {
61+
plainVector[i] += inverseKeyMatrix[i][j] * messageVector[j];
10762
}
108-
109-
plainMatrix[i][0] = plainMatrix[i][0] % 26;
110-
}
111-
for (i = 0; i < n; i++) {
112-
plainText += (char) (plainMatrix[i][0] + 65);
63+
plainVector[i] = plainVector[i] % 26;
64+
plainText.append((char) (plainVector[i] + 'A'));
11365
}
11466
}
115-
System.out.println("Plaintext: " + plainText);
67+
68+
return plainText.toString();
11669
}
11770

118-
// Determinant calculator
119-
public static int determinant(int[][] a, int n) {
120-
int det = 0;
121-
int sign = 1;
122-
int p = 0;
123-
int q = 0;
71+
// Validates that the determinant of the key matrix is not zero modulo 26
72+
private void validateDeterminant(int[][] keyMatrix, int n) {
73+
int det = determinant(keyMatrix, n) % 26;
74+
if (det == 0) {
75+
throw new IllegalArgumentException("Invalid key matrix. Determinant is zero modulo 26.");
76+
}
77+
}
12478

79+
// Computes the determinant of a matrix recursively
80+
private int determinant(int[][] matrix, int n) {
81+
int det = 0;
12582
if (n == 1) {
126-
det = a[0][0];
127-
} else {
128-
int[][] b = new int[n - 1][n - 1];
129-
for (int x = 0; x < n; x++) {
130-
p = 0;
131-
q = 0;
132-
for (int i = 1; i < n; i++) {
133-
for (int j = 0; j < n; j++) {
134-
if (j != x) {
135-
b[p][q++] = a[i][j];
136-
if (q % (n - 1) == 0) {
137-
p++;
138-
q = 0;
139-
}
140-
}
83+
return matrix[0][0];
84+
}
85+
int sign = 1;
86+
int[][] subMatrix = new int[n - 1][n - 1];
87+
for (int x = 0; x < n; x++) {
88+
int subI = 0;
89+
for (int i = 1; i < n; i++) {
90+
int subJ = 0;
91+
for (int j = 0; j < n; j++) {
92+
if (j != x) {
93+
subMatrix[subI][subJ++] = matrix[i][j];
14194
}
14295
}
143-
det = det + a[0][x] * determinant(b, n - 1) * sign;
144-
sign = -sign;
96+
subI++;
14597
}
98+
det += sign * matrix[0][x] * determinant(subMatrix, n - 1);
99+
sign = -sign;
146100
}
147101
return det;
148102
}
149-
150-
// Function to implement Hill Cipher
151-
static void hillCipher(String message) {
152-
System.out.println("What do you want to process from the message?");
153-
System.out.println("Press 1: To Encrypt");
154-
System.out.println("Press 2: To Decrypt");
155-
short sc = userInput.nextShort();
156-
if (sc == 1) {
157-
encrypt(message);
158-
} else if (sc == 2) {
159-
decrypt(message);
160-
} else {
161-
System.out.println("Invalid input, program terminated.");
162-
}
163-
}
164-
165-
static void validateDeterminant(int[][] keyMatrix, int n) {
166-
if (determinant(keyMatrix, n) % 26 == 0) {
167-
System.out.println("Invalid key, as determinant = 0. Program Terminated");
168-
}
169-
}
170-
171-
// Driver code
172-
public static void main(String[] args) {
173-
// Get the message to be encrypted
174-
System.out.println("Enter message");
175-
String message = userInput.nextLine();
176-
hillCipher(message);
177-
}
178103
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
class HillCipherTest {
8+
9+
HillCipher hillCipher = new HillCipher();
10+
11+
@Test
12+
void hillCipherEncryptTest() {
13+
// given
14+
String message = "ACT"; // Plaintext message
15+
int[][] keyMatrix = {{6, 24, 1}, {13, 16, 10}, {20, 17, 15}}; // Encryption key matrix
16+
17+
// when
18+
String cipherText = hillCipher.encrypt(message, keyMatrix);
19+
20+
// then
21+
assertEquals("POH", cipherText);
22+
}
23+
24+
@Test
25+
void hillCipherDecryptTest() {
26+
// given
27+
String cipherText = "POH"; // Ciphertext message
28+
int[][] inverseKeyMatrix = {{8, 5, 10}, {21, 8, 21}, {21, 12, 8}}; // Decryption (inverse key) matrix
29+
30+
// when
31+
String plainText = hillCipher.decrypt(cipherText, inverseKeyMatrix);
32+
33+
// then
34+
assertEquals("ACT", plainText);
35+
}
36+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy