Skip to content

Add Junit tests for AffineCipher.java, improve documentation #5598

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

Merged
merged 6 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@
* [A5KeyStreamGeneratorTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/ciphers/a5/A5KeyStreamGeneratorTest.java)
* [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)
* [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 Down
51 changes: 40 additions & 11 deletions src/main/java/com/thealgorithms/ciphers/AffineCipher.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
package com.thealgorithms.ciphers;

/**
* The AffineCipher class implements the Affine cipher, a type of monoalphabetic substitution cipher.
* It encrypts and decrypts messages using a linear transformation defined by the formula:
*
* E(x) = (a * x + b) mod m
* D(y) = a^-1 * (y - b) mod m
*
* where:
* - E(x) is the encrypted character,
* - D(y) is the decrypted character,
* - a is the multiplicative key (must be coprime to m),
* - b is the additive key,
* - x is the index of the plaintext character,
* - y is the index of the ciphertext character,
* - m is the size of the alphabet (26 for the English alphabet).
*
* The class provides methods for encrypting and decrypting messages, as well as a main method to demonstrate its usage.
*/
final class AffineCipher {
private AffineCipher() {
}
Expand All @@ -8,45 +26,56 @@ private AffineCipher() {
static int a = 17;
static int b = 20;

/**
* Encrypts a message using the Affine cipher.
*
* @param msg the plaintext message as a character array
* @return the encrypted ciphertext
*/
static String encryptMessage(char[] msg) {
/// Cipher Text initially empty
// Cipher Text initially empty
String cipher = "";
for (int i = 0; i < msg.length; i++) {
// Avoid space to be encrypted
/* applying encryption formula ( a x + b ) mod m
/* applying encryption formula ( a * x + b ) mod m
{here x is msg[i] and m is 26} and added 'A' to
bring it in range of ascii alphabet[ 65-90 | A-Z ] */
bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (msg[i] != ' ') {
cipher = cipher + (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
cipher += (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
} else { // else simply append space character
cipher += msg[i];
}
}
return cipher;
}

/**
* Decrypts a ciphertext using the Affine cipher.
*
* @param cipher the ciphertext to decrypt
* @return the decrypted plaintext message
*/
static String decryptCipher(String cipher) {
String msg = "";
int aInv = 0;
int flag = 0;
int flag;

// Find a^-1 (the multiplicative inverse of a
// in the group of integers modulo m.)
// Find a^-1 (the multiplicative inverse of a in the group of integers modulo m.)
for (int i = 0; i < 26; i++) {
flag = (a * i) % 26;

// Check if (a*i)%26 == 1,
// Check if (a * i) % 26 == 1,
// then i will be the multiplicative inverse of a
if (flag == 1) {
aInv = i;
}
}
for (int i = 0; i < cipher.length(); i++) {
/*Applying decryption formula a^-1 ( x - b ) mod m
/* Applying decryption formula a^-1 * (x - b) mod m
{here x is cipher[i] and m is 26} and added 'A'
to bring it in range of ASCII alphabet[ 65-90 | A-Z ] */
to bring it in the range of ASCII alphabet [65-90 | A-Z] */
if (cipher.charAt(i) != ' ') {
msg = msg + (char) (((aInv * ((cipher.charAt(i) + 'A' - b)) % 26)) + 'A');
msg += (char) (((aInv * ((cipher.charAt(i) - 'A') - b + 26)) % 26) + 'A');
} else { // else simply append space character
msg += cipher.charAt(i);
}
Expand Down
39 changes: 39 additions & 0 deletions src/test/java/com/thealgorithms/ciphers/AffineCipherTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.thealgorithms.ciphers;

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

import org.junit.jupiter.api.Test;

public class AffineCipherTest {

@Test
public void testEncryptMessage() {
String plaintext = "AFFINE CIPHER";
char[] msg = plaintext.toCharArray();
String expectedCiphertext = "UBBAHK CAPJKX"; // Expected ciphertext after encryption

String actualCiphertext = AffineCipher.encryptMessage(msg);
assertEquals(expectedCiphertext, actualCiphertext, "The encryption result should match the expected ciphertext.");
}

@Test
public void testEncryptDecrypt() {
String plaintext = "HELLO WORLD";
char[] msg = plaintext.toCharArray();

String ciphertext = AffineCipher.encryptMessage(msg);
String decryptedText = AffineCipher.decryptCipher(ciphertext);

assertEquals(plaintext, decryptedText, "Decrypted text should match the original plaintext.");
}

@Test
public void testSpacesHandledInEncryption() {
String plaintext = "HELLO WORLD";
char[] msg = plaintext.toCharArray();
String expectedCiphertext = "JKZZY EYXZT";

String actualCiphertext = AffineCipher.encryptMessage(msg);
assertEquals(expectedCiphertext, actualCiphertext, "The encryption should handle spaces correctly.");
}
}