Skip to content

Commit fba5058

Browse files
committed
Add: ElGamal Encryption Algorithm with tests
1 parent b48f2f4 commit fba5058

File tree

2 files changed

+42
-38
lines changed

2 files changed

+42
-38
lines changed

src/main/java/com/thealgorithms/ciphers/ElGamalEncryption.java

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,3 @@
1-
/*
2-
* TheAlgorithms (https://github.com/TheAlgorithms/Java)
3-
* Author: Shewale41
4-
* This file is licensed under the MIT License.
5-
*/
6-
71
package com.thealgorithms.ciphers;
82

93
import java.math.BigInteger;
@@ -12,44 +6,49 @@
126
/**
137
* Implementation of the ElGamal Encryption Algorithm.
148
*
15-
* <p>This algorithm is based on the Diffie–Hellman key exchange and provides secure
16-
* public-key encryption and decryption using modular arithmetic.
9+
* <p>ElGamal is an asymmetric key encryption algorithm based on
10+
* the Diffie–Hellman key exchange. It uses randomization
11+
* for security and is widely used in cryptographic systems.</p>
1712
*
18-
* <p>Reference:
19-
* https://en.wikipedia.org/wiki/ElGamal_encryption
13+
* <p>Reference: Menezes, van Oorschot, and Vanstone, "Handbook of Applied Cryptography"</p>
2014
*/
2115
public final class ElGamalEncryption {
2216

2317
private static final SecureRandom RANDOM = new SecureRandom();
2418

25-
/** Private constructor to prevent instantiation of utility class. */
19+
// Private constructor to prevent instantiation
2620
private ElGamalEncryption() {
2721
throw new UnsupportedOperationException("Utility class");
2822
}
2923

3024
/**
31-
* Demonstrates ElGamal encryption and decryption for a given message.
25+
* Runs the ElGamal encryption and decryption demonstration.
3226
*
33-
* @param message the message to encrypt
34-
* @param bitLength the bit length for the prime number used
27+
* @param message the plaintext message to encrypt
28+
* @param bitLength the bit length for prime generation
3529
*/
36-
public static void runElGamal(String message, int bitLength) {
37-
BigInteger p = BigInteger.probablePrime(bitLength, RANDOM); // prime modulus
38-
BigInteger g = new BigInteger("2"); // primitive root
39-
BigInteger x = new BigInteger(bitLength - 2, RANDOM); // private key
40-
BigInteger y = g.modPow(x, p); // public key
30+
@SuppressWarnings({"PMD.SystemPrintln", "PMD.DataflowAnomalyAnalysis"})
31+
public static void runElGamal(final String message, final int bitLength) {
32+
// Key generation
33+
final BigInteger p = BigInteger.probablePrime(bitLength, RANDOM);
34+
final BigInteger g = new BigInteger("2");
35+
final BigInteger x = new BigInteger(bitLength - 2, RANDOM);
36+
final BigInteger y = g.modPow(x, p);
4137

4238
// Encryption
43-
BigInteger k = new BigInteger(bitLength - 2, RANDOM);
44-
BigInteger a = g.modPow(k, p);
45-
BigInteger m = new BigInteger(message.getBytes());
46-
BigInteger b = (y.modPow(k, p).multiply(m)).mod(p);
39+
final BigInteger k = new BigInteger(bitLength - 2, RANDOM);
40+
final BigInteger a = g.modPow(k, p);
41+
final BigInteger m = new BigInteger(message.getBytes());
42+
final BigInteger b = (y.modPow(k, p).multiply(m)).mod(p);
4743

4844
// Decryption
49-
BigInteger aInverse = a.modPow(p.subtract(BigInteger.ONE).subtract(x), p);
50-
BigInteger decrypted = (b.multiply(aInverse)).mod(p);
45+
final BigInteger aInverse = a.modPow(p.subtract(BigInteger.ONE).subtract(x), p);
46+
final BigInteger decrypted = (b.multiply(aInverse)).mod(p);
5147

48+
// Display results
5249
System.out.println("Prime (p): " + p);
50+
System.out.println("Generator (g): " + g);
51+
System.out.println("Private Key (x): " + x);
5352
System.out.println("Public Key (y): " + y);
5453
System.out.println("Ciphertext: (" + a + ", " + b + ")");
5554
System.out.println("Decrypted Message: " + new String(decrypted.toByteArray()));
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,34 @@
1-
/*
2-
* TheAlgorithms (https://github.com/TheAlgorithms/Java)
3-
* Author: Shewale41
4-
* This file is licensed under the MIT License.
5-
*/
6-
71
package com.thealgorithms.ciphers;
82

9-
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
104

115
import org.junit.jupiter.api.Test;
126

137
/**
14-
* Tests for {@link ElGamalEncryption}.
8+
* Unit tests for {@link ElGamalEncryption}.
159
*/
1610
public class ElGamalEncryptionTest {
1711

1812
@Test
1913
void testEncryptionDecryption() {
20-
String message = "Hello";
21-
assertDoesNotThrow(() -> ElGamalEncryption.runElGamal(message, 32));
14+
// Basic functional test (simulated output check)
15+
// Since ElGamal uses randomization, we only verify successful execution
16+
try {
17+
ElGamalEncryption.runElGamal("Hello", 64);
18+
} catch (Exception e) {
19+
throw new AssertionError("ElGamalEncryption failed with exception: " + e.getMessage());
20+
}
2221
}
2322

2423
@Test
25-
void testWithDifferentBitLengths() {
26-
assertDoesNotThrow(() -> ElGamalEncryption.runElGamal("Test", 16));
27-
assertDoesNotThrow(() -> ElGamalEncryption.runElGamal("Secure", 64));
24+
void testUtilityConstructor() {
25+
// Ensures the utility class constructor is private
26+
try {
27+
var constructor = ElGamalEncryption.class.getDeclaredConstructor();
28+
constructor.setAccessible(true);
29+
constructor.newInstance();
30+
} catch (Exception e) {
31+
assertEquals("Utility class", e.getCause().getMessage());
32+
}
2833
}
2934
}

0 commit comments

Comments
 (0)