Skip to content

Commit c56d282

Browse files
authored
Add DiffieHellman and MonoAlphabetic (#5508)
1 parent 5a1f681 commit c56d282

File tree

4 files changed

+151
-0
lines changed

4 files changed

+151
-0
lines changed
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 java.math.BigInteger;
4+
5+
public final class DiffieHellman {
6+
7+
private final BigInteger base;
8+
private final BigInteger secret;
9+
private final BigInteger prime;
10+
11+
// Constructor to initialize base, secret, and prime
12+
public DiffieHellman(BigInteger base, BigInteger secret, BigInteger prime) {
13+
// Check for non-null and positive values
14+
if (base == null || secret == null || prime == null || base.signum() <= 0 || secret.signum() <= 0 || prime.signum() <= 0) {
15+
throw new IllegalArgumentException("Base, secret, and prime must be non-null and positive values.");
16+
}
17+
this.base = base;
18+
this.secret = secret;
19+
this.prime = prime;
20+
}
21+
22+
// Method to calculate public value (g^x mod p)
23+
public BigInteger calculatePublicValue() {
24+
// Returns g^x mod p
25+
return base.modPow(secret, prime);
26+
}
27+
28+
// Method to calculate the shared secret key (otherPublic^secret mod p)
29+
public BigInteger calculateSharedSecret(BigInteger otherPublicValue) {
30+
if (otherPublicValue == null || otherPublicValue.signum() <= 0) {
31+
throw new IllegalArgumentException("Other public value must be non-null and positive.");
32+
}
33+
// Returns b^x mod p or a^y mod p
34+
return otherPublicValue.modPow(secret, prime);
35+
}
36+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package com.thealgorithms.ciphers;
2+
3+
public final class MonoAlphabetic {
4+
5+
private MonoAlphabetic() {
6+
throw new UnsupportedOperationException("Utility class");
7+
}
8+
9+
// Encryption method
10+
public static String encrypt(String data, String key) {
11+
if (!data.matches("[A-Z]+")) {
12+
throw new IllegalArgumentException("Input data contains invalid characters. Only uppercase A-Z are allowed.");
13+
}
14+
StringBuilder sb = new StringBuilder();
15+
16+
// Encrypt each character
17+
for (char c : data.toCharArray()) {
18+
int idx = charToPos(c); // Get the index of the character
19+
sb.append(key.charAt(idx)); // Map to the corresponding character in the key
20+
}
21+
return sb.toString();
22+
}
23+
24+
// Decryption method
25+
public static String decrypt(String data, String key) {
26+
StringBuilder sb = new StringBuilder();
27+
28+
// Decrypt each character
29+
for (char c : data.toCharArray()) {
30+
int idx = key.indexOf(c); // Find the index of the character in the key
31+
if (idx == -1) {
32+
throw new IllegalArgumentException("Input data contains invalid characters.");
33+
}
34+
sb.append(posToChar(idx)); // Convert the index back to the original character
35+
}
36+
return sb.toString();
37+
}
38+
39+
// Helper method: Convert a character to its position in the alphabet
40+
private static int charToPos(char c) {
41+
return c - 'A'; // Subtract 'A' to get position (0 for A, 1 for B, etc.)
42+
}
43+
44+
// Helper method: Convert a position in the alphabet to a character
45+
private static char posToChar(int pos) {
46+
return (char) (pos + 'A'); // Add 'A' to convert position back to character
47+
}
48+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.math.BigInteger;
6+
import java.util.stream.Stream;
7+
import org.junit.jupiter.params.ParameterizedTest;
8+
import org.junit.jupiter.params.provider.Arguments;
9+
import org.junit.jupiter.params.provider.MethodSource;
10+
11+
public class DiffieHellmanTest {
12+
13+
// Test for public value calculation using instance methods
14+
@ParameterizedTest
15+
@MethodSource("provideTestData")
16+
public void testCalculatePublicValue(BigInteger base, BigInteger secret, BigInteger prime, BigInteger publicExpected, BigInteger sharedExpected) {
17+
DiffieHellman dh = new DiffieHellman(base, secret, prime); // Create an instance of DiffieHellman
18+
assertEquals(publicExpected, dh.calculatePublicValue()); // Call instance method
19+
}
20+
21+
// Test for shared secret calculation using instance methods
22+
@ParameterizedTest
23+
@MethodSource("provideTestData")
24+
public void testCalculateSharedSecret(BigInteger base, BigInteger secret, BigInteger prime, BigInteger publicExpected, BigInteger sharedExpected) {
25+
DiffieHellman dh = new DiffieHellman(base, secret, prime); // Create an instance of DiffieHellman
26+
assertEquals(sharedExpected, dh.calculateSharedSecret(publicExpected)); // Call instance method
27+
}
28+
29+
// Provide test data for both public key and shared secret calculation
30+
private static Stream<Arguments> provideTestData() {
31+
return Stream.of(createTestArgs(5, 6, 23, 8, 13), createTestArgs(2, 5, 13, 6, 2));
32+
}
33+
34+
// Helper method for arguments
35+
private static Arguments createTestArgs(long base, long secret, long prime, long publicExpected, long sharedExpected) {
36+
return Arguments.of(BigInteger.valueOf(base), BigInteger.valueOf(secret), BigInteger.valueOf(prime), BigInteger.valueOf(publicExpected), BigInteger.valueOf(sharedExpected));
37+
}
38+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.thealgorithms.ciphers;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import java.util.stream.Stream;
6+
import org.junit.jupiter.params.ParameterizedTest;
7+
import org.junit.jupiter.params.provider.Arguments;
8+
import org.junit.jupiter.params.provider.MethodSource;
9+
10+
public class MonoAlphabeticTest {
11+
12+
// Test for both encryption and decryption with different keys
13+
@ParameterizedTest
14+
@MethodSource("provideTestData")
15+
public void testEncryptDecrypt(String plainText, String key, String encryptedText) {
16+
// Test encryption
17+
String actualEncrypted = MonoAlphabetic.encrypt(plainText, key);
18+
assertEquals(encryptedText, actualEncrypted, "Encryption failed for input: " + plainText + " with key: " + key);
19+
20+
// Test decryption
21+
String actualDecrypted = MonoAlphabetic.decrypt(encryptedText, key);
22+
assertEquals(plainText, actualDecrypted, "Decryption failed for input: " + encryptedText + " with key: " + key);
23+
}
24+
25+
// Provide test data for both encryption and decryption
26+
private static Stream<Arguments> provideTestData() {
27+
return Stream.of(Arguments.of("HELLO", "MNBVCXZLKJHGFDSAPOIUYTREWQ", "LCGGS"), Arguments.of("JAVA", "MNBVCXZLKJHGFDSAPOIUYTREWQ", "JMTM"), Arguments.of("HELLO", "QWERTYUIOPLKJHGFDSAZXCVBNM", "ITKKG"), Arguments.of("JAVA", "QWERTYUIOPLKJHGFDSAZXCVBNM", "PQCQ"));
28+
}
29+
}

0 commit comments

Comments
 (0)