Skip to content

Commit 80d1ebd

Browse files
authored
Merge branch 'master' into leftist_heap_improve
2 parents d5df3ae + 709d977 commit 80d1ebd

27 files changed

+1346
-111
lines changed

DIRECTORY.md

Lines changed: 17 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.thealgorithms.bitmanipulation;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
6+
/**
7+
* This class provides a method to generate all subsets (power set)
8+
* of a given set using bit manipulation.
9+
*
10+
* @author Hardvan
11+
*/
12+
public final class GenerateSubsets {
13+
private GenerateSubsets() {
14+
}
15+
16+
/**
17+
* Generates all subsets of a given set using bit manipulation.
18+
* Steps:
19+
* 1. Iterate over all numbers from 0 to 2^n - 1.
20+
* 2. For each number, iterate over all bits from 0 to n - 1.
21+
* 3. If the i-th bit of the number is set, add the i-th element of the set to the current subset.
22+
* 4. Add the current subset to the list of subsets.
23+
* 5. Return the list of subsets.
24+
*
25+
* @param set the input set of integers
26+
* @return a list of all subsets represented as lists of integers
27+
*/
28+
public static List<List<Integer>> generateSubsets(int[] set) {
29+
int n = set.length;
30+
List<List<Integer>> subsets = new ArrayList<>();
31+
32+
for (int mask = 0; mask < (1 << n); mask++) {
33+
List<Integer> subset = new ArrayList<>();
34+
for (int i = 0; i < n; i++) {
35+
if ((mask & (1 << i)) != 0) {
36+
subset.add(set[i]);
37+
}
38+
}
39+
subsets.add(subset);
40+
}
41+
42+
return subsets;
43+
}
44+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.thealgorithms.bitmanipulation;
2+
3+
/**
4+
* This class provides a method to find the next higher number
5+
* with the same number of set bits as the given number.
6+
*
7+
* @author Hardvan
8+
*/
9+
public final class NextHigherSameBitCount {
10+
private NextHigherSameBitCount() {
11+
}
12+
13+
/**
14+
* Finds the next higher integer with the same number of set bits.
15+
* Steps:
16+
* 1. Find {@code c}, the rightmost set bit of {@code n}.
17+
* 2. Find {@code r}, the rightmost set bit of {@code n + c}.
18+
* 3. Swap the bits of {@code r} and {@code n} to the right of {@code c}.
19+
* 4. Shift the bits of {@code r} and {@code n} to the right of {@code c} to the rightmost.
20+
* 5. Combine the results of steps 3 and 4.
21+
*
22+
* @param n the input number
23+
* @return the next higher integer with the same set bit count
24+
*/
25+
public static int nextHigherSameBitCount(int n) {
26+
int c = n & -n;
27+
int r = n + c;
28+
return (((r ^ n) >> 2) / c) | r;
29+
}
30+
}

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

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,38 @@
33
import java.util.Arrays;
44
import java.util.HashMap;
55
import java.util.Map;
6+
67
/**
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
8+
* The ADFGVX cipher is a fractionating transposition cipher that was used by
9+
* the German Army during World War I. It combines a **Polybius square substitution**
10+
* with a **columnar transposition** to enhance encryption strength.
11+
* <p>
12+
* The name "ADFGVX" refers to the six letters (A, D, F, G, V, X) used as row and
13+
* column labels in the Polybius square. This cipher was designed to secure
14+
* communication and create complex, hard-to-break ciphertexts.
15+
* <p>
16+
* Learn more: <a href="https://en.wikipedia.org/wiki/ADFGVX_cipher">ADFGVX Cipher - Wikipedia</a>.
17+
* <p>
18+
* Example usage:
19+
* <pre>
20+
* ADFGVXCipher cipher = new ADFGVXCipher();
21+
* String encrypted = cipher.encrypt("attack at 1200am", "PRIVACY");
22+
* String decrypted = cipher.decrypt(encrypted, "PRIVACY");
23+
* </pre>
1324
*
1425
* @author bennybebo
1526
*/
1627
public class ADFGVXCipher {
1728

29+
// Constants used in the Polybius square
1830
private static final char[] POLYBIUS_LETTERS = {'A', 'D', 'F', 'G', 'V', 'X'};
1931
private static final char[][] POLYBIUS_SQUARE = {{'N', 'A', '1', 'C', '3', 'H'}, {'8', 'T', 'B', '2', 'O', 'M'}, {'E', '5', 'W', 'R', 'P', 'D'}, {'4', 'F', '6', 'G', '7', 'I'}, {'9', 'J', '0', 'K', 'L', 'Q'}, {'S', 'U', 'V', 'X', 'Y', 'Z'}};
32+
33+
// Maps for fast substitution lookups
2034
private static final Map<String, Character> POLYBIUS_MAP = new HashMap<>();
2135
private static final Map<Character, String> REVERSE_POLYBIUS_MAP = new HashMap<>();
2236

37+
// Static block to initialize the lookup tables from the Polybius square
2338
static {
2439
for (int i = 0; i < POLYBIUS_SQUARE.length; i++) {
2540
for (int j = 0; j < POLYBIUS_SQUARE[i].length; j++) {
@@ -30,26 +45,41 @@ public class ADFGVXCipher {
3045
}
3146
}
3247

33-
// Encrypts the plaintext using the ADFGVX cipher
48+
/**
49+
* Encrypts a given plaintext using the ADFGVX cipher with the provided keyword.
50+
* Steps:
51+
* 1. Substitute each letter in the plaintext with a pair of ADFGVX letters.
52+
* 2. Perform a columnar transposition on the fractionated text using the keyword.
53+
*
54+
* @param plaintext The message to be encrypted (can contain letters and digits).
55+
* @param key The keyword for columnar transposition.
56+
* @return The encrypted message as ciphertext.
57+
*/
3458
public String encrypt(String plaintext, String key) {
35-
plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", "");
59+
plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", ""); // Sanitize input
3660
StringBuilder fractionatedText = new StringBuilder();
3761

38-
// Step 1: Polybius square substitution
3962
for (char c : plaintext.toCharArray()) {
4063
fractionatedText.append(REVERSE_POLYBIUS_MAP.get(c));
4164
}
4265

43-
// Step 2: Columnar transposition
4466
return columnarTransposition(fractionatedText.toString(), key);
4567
}
4668

47-
// Decrypts the ciphertext using the ADFGVX cipher
69+
/**
70+
* Decrypts a given ciphertext using the ADFGVX cipher with the provided keyword.
71+
* Steps:
72+
* 1. Reverse the columnar transposition performed during encryption.
73+
* 2. Substitute each pair of ADFGVX letters with the corresponding plaintext letter.
74+
* The resulting text is the decrypted message.
75+
*
76+
* @param ciphertext The encrypted message.
77+
* @param key The keyword used during encryption.
78+
* @return The decrypted plaintext message.
79+
*/
4880
public String decrypt(String ciphertext, String key) {
49-
// Step 1: Reverse the columnar transposition
5081
String fractionatedText = reverseColumnarTransposition(ciphertext, key);
5182

52-
// Step 2: Polybius square substitution
5383
StringBuilder plaintext = new StringBuilder();
5484
for (int i = 0; i < fractionatedText.length(); i += 2) {
5585
String pair = fractionatedText.substring(i, i + 2);
@@ -59,14 +89,21 @@ public String decrypt(String ciphertext, String key) {
5989
return plaintext.toString();
6090
}
6191

92+
/**
93+
* Helper method: Performs columnar transposition during encryption
94+
*
95+
* @param text The fractionated text to be transposed
96+
* @param key The keyword for columnar transposition
97+
* @return The transposed text
98+
*/
6299
private String columnarTransposition(String text, String key) {
63100
int numRows = (int) Math.ceil((double) text.length() / key.length());
64101
char[][] table = new char[numRows][key.length()];
65-
for (char[] row : table) {
66-
Arrays.fill(row, '_'); // Fill with underscores to handle empty cells
102+
for (char[] row : table) { // Fill empty cells with underscores
103+
Arrays.fill(row, '_');
67104
}
68105

69-
// Fill the table row by row
106+
// Populate the table row by row
70107
for (int i = 0; i < text.length(); i++) {
71108
table[i / key.length()][i % key.length()] = text.charAt(i);
72109
}
@@ -88,6 +125,13 @@ private String columnarTransposition(String text, String key) {
88125
return ciphertext.toString();
89126
}
90127

128+
/**
129+
* Helper method: Reverses the columnar transposition during decryption
130+
*
131+
* @param ciphertext The transposed text to be reversed
132+
* @param key The keyword used during encryption
133+
* @return The reversed text
134+
*/
91135
private String reverseColumnarTransposition(String ciphertext, String key) {
92136
int numRows = (int) Math.ceil((double) ciphertext.length() / key.length());
93137
char[][] table = new char[numRows][key.length()];
@@ -96,19 +140,19 @@ private String reverseColumnarTransposition(String ciphertext, String key) {
96140
Arrays.sort(sortedKey);
97141

98142
int index = 0;
99-
// Fill the table column by column according to the sorted key order
143+
// Populate the table column by column according to the sorted key
100144
for (char keyChar : sortedKey) {
101145
int column = key.indexOf(keyChar);
102146
for (int row = 0; row < numRows; row++) {
103147
if (index < ciphertext.length()) {
104148
table[row][column] = ciphertext.charAt(index++);
105149
} else {
106-
table[row][column] = '_'; // Fill empty cells with an underscore
150+
table[row][column] = '_';
107151
}
108152
}
109153
}
110154

111-
// Read the table row by row to get the fractionated text
155+
// Read the table row by row to reconstruct the fractionated text
112156
StringBuilder fractionatedText = new StringBuilder();
113157
for (char[] row : table) {
114158
for (char cell : row) {

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

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,63 +4,116 @@
44
import java.security.SecureRandom;
55

66
/**
7-
* @author Nguyen Duy Tiep on 23-Oct-17.
7+
* RSA is an asymmetric cryptographic algorithm used for secure data encryption and decryption.
8+
* It relies on a pair of keys: a public key (used for encryption) and a private key
9+
* (used for decryption). The algorithm is based on the difficulty of factoring large prime numbers.
10+
*
11+
* This implementation includes key generation, encryption, and decryption methods that can handle both
12+
* text-based messages and BigInteger inputs. For more details on RSA:
13+
* <a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)">RSA Cryptosystem - Wikipedia</a>.
14+
*
15+
* Example Usage:
16+
* <pre>
17+
* RSA rsa = new RSA(1024);
18+
* String encryptedMessage = rsa.encrypt("Hello RSA!");
19+
* String decryptedMessage = rsa.decrypt(encryptedMessage);
20+
* System.out.println(decryptedMessage); // Output: Hello RSA!
21+
* </pre>
22+
*
23+
* Note: The key size directly affects the security and performance of the RSA algorithm.
24+
* Larger keys are more secure but slower to compute.
25+
*
26+
* @author Nguyen Duy Tiep
27+
* @version 23-Oct-17
828
*/
929
public class RSA {
1030

1131
private BigInteger modulus;
1232
private BigInteger privateKey;
1333
private BigInteger publicKey;
1434

35+
/**
36+
* Constructor that generates RSA keys with the specified number of bits.
37+
*
38+
* @param bits The bit length of the keys to be generated. Common sizes include 512, 1024, 2048, etc.
39+
*/
1540
public RSA(int bits) {
1641
generateKeys(bits);
1742
}
1843

1944
/**
20-
* @return encrypted message
45+
* Encrypts a text message using the RSA public key.
46+
*
47+
* @param message The plaintext message to be encrypted.
48+
* @throws IllegalArgumentException If the message is empty.
49+
* @return The encrypted message represented as a String.
2150
*/
2251
public synchronized String encrypt(String message) {
52+
if (message.isEmpty()) {
53+
throw new IllegalArgumentException("Message is empty");
54+
}
2355
return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
2456
}
2557

2658
/**
27-
* @return encrypted message as big integer
59+
* Encrypts a BigInteger message using the RSA public key.
60+
*
61+
* @param message The plaintext message as a BigInteger.
62+
* @return The encrypted message as a BigInteger.
2863
*/
2964
public synchronized BigInteger encrypt(BigInteger message) {
3065
return message.modPow(publicKey, modulus);
3166
}
3267

3368
/**
34-
* @return plain message
69+
* Decrypts an encrypted message (as String) using the RSA private key.
70+
*
71+
* @param encryptedMessage The encrypted message to be decrypted, represented as a String.
72+
* @throws IllegalArgumentException If the message is empty.
73+
* @return The decrypted plaintext message as a String.
3574
*/
3675
public synchronized String decrypt(String encryptedMessage) {
76+
if (encryptedMessage.isEmpty()) {
77+
throw new IllegalArgumentException("Message is empty");
78+
}
3779
return new String((new BigInteger(encryptedMessage)).modPow(privateKey, modulus).toByteArray());
3880
}
3981

4082
/**
41-
* @return plain message as big integer
83+
* Decrypts an encrypted BigInteger message using the RSA private key.
84+
*
85+
* @param encryptedMessage The encrypted message as a BigInteger.
86+
* @return The decrypted plaintext message as a BigInteger.
4287
*/
4388
public synchronized BigInteger decrypt(BigInteger encryptedMessage) {
4489
return encryptedMessage.modPow(privateKey, modulus);
4590
}
4691

4792
/**
48-
* Generate a new public and private key set.
93+
* Generates a new RSA key pair (public and private keys) with the specified bit length.
94+
* Steps:
95+
* 1. Generate two large prime numbers p and q.
96+
* 2. Compute the modulus n = p * q.
97+
* 3. Compute Euler's totient function: φ(n) = (p-1) * (q-1).
98+
* 4. Choose a public key e (starting from 3) that is coprime with φ(n).
99+
* 5. Compute the private key d as the modular inverse of e mod φ(n).
100+
* The public key is (e, n) and the private key is (d, n).
101+
*
102+
* @param bits The bit length of the keys to be generated.
49103
*/
50104
public final synchronized void generateKeys(int bits) {
51-
SecureRandom r = new SecureRandom();
52-
BigInteger p = new BigInteger(bits / 2, 100, r);
53-
BigInteger q = new BigInteger(bits / 2, 100, r);
105+
SecureRandom random = new SecureRandom();
106+
BigInteger p = new BigInteger(bits / 2, 100, random);
107+
BigInteger q = new BigInteger(bits / 2, 100, random);
54108
modulus = p.multiply(q);
55109

56-
BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
110+
BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
57111

58112
publicKey = BigInteger.valueOf(3L);
59-
60-
while (m.gcd(publicKey).intValue() > 1) {
113+
while (phi.gcd(publicKey).intValue() > 1) {
61114
publicKey = publicKey.add(BigInteger.TWO);
62115
}
63116

64-
privateKey = publicKey.modInverse(m);
117+
privateKey = publicKey.modInverse(phi);
65118
}
66119
}

0 commit comments

Comments
 (0)