>> "+wordBeingEncrypted);
- System.out.println("Word encrypted ->>> "+ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted,keywordForExample));
- System.out.println("Word decryped ->>> "+ColumnarTranspositionCipher.decrypter());
- System.out.println("\n### Encrypted Table ###");
- showTable();
- }
-}
diff --git a/ciphers/RSA.java b/ciphers/RSA.java
deleted file mode 100644
index 5baa61b0424d..000000000000
--- a/ciphers/RSA.java
+++ /dev/null
@@ -1,62 +0,0 @@
-package ciphers;
-
-import java.math.BigInteger;
-import java.security.SecureRandom;
-
-/**
- * Created by Nguyen Duy Tiep on 23-Oct-17.
- */
-public class RSA {
- private BigInteger modulus, privateKey, publicKey;
-
- public RSA(int bits) {
- generateKeys(bits);
- }
-
- public synchronized String encrypt(String message) {
- return (new BigInteger(message.getBytes())).modPow(publicKey, modulus).toString();
- }
-
- public synchronized BigInteger encrypt(BigInteger message) {
- return message.modPow(publicKey, modulus);
- }
-
- public synchronized String decrypt(String message) {
- return new String((new BigInteger(message)).modPow(privateKey, modulus).toByteArray());
- }
-
- public synchronized BigInteger decrypt(BigInteger message) {
- return message.modPow(privateKey, modulus);
- }
-
- /** Generate a new public and private key set. */
- public synchronized void generateKeys(int bits) {
- SecureRandom r = new SecureRandom();
- BigInteger p = new BigInteger(bits / 2, 100, r);
- BigInteger q = new BigInteger(bits / 2, 100, r);
- modulus = p.multiply(q);
-
- BigInteger m = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE));
-
- publicKey = new BigInteger("3");
-
- while (m.gcd(publicKey).intValue() > 1) {
- publicKey = publicKey.add(new BigInteger("2"));
- }
-
- privateKey = publicKey.modInverse(m);
- }
-
- /** Trivial test program. */
- public static void main(String[] args) {
- RSA rsa = new RSA(1024);
-
- String text1 = "This is a message";
- System.out.println("Plaintext: " + text1);
-
- String ciphertext = rsa.encrypt(text1);
- System.out.println("Ciphertext: " + ciphertext);
-
- System.out.println("Plaintext: " + rsa.decrypt(ciphertext));
- }
-}
diff --git a/pmd-custom_ruleset.xml b/pmd-custom_ruleset.xml
new file mode 100644
index 000000000000..19bb1c7968f0
--- /dev/null
+++ b/pmd-custom_ruleset.xml
@@ -0,0 +1,28 @@
+
+
+
+ Custom PMD checks for TheAlgorithms/Java
+
+
+
+ Avoid using the main method.
+
+ 3
+
+
+
+
+
+
+
+
+
diff --git a/pmd-exclude.properties b/pmd-exclude.properties
new file mode 100644
index 000000000000..a3c95b12fa4b
--- /dev/null
+++ b/pmd-exclude.properties
@@ -0,0 +1,122 @@
+com.thealgorithms.ciphers.AES=UselessMainMethod
+com.thealgorithms.ciphers.AESEncryption=UselessMainMethod
+com.thealgorithms.ciphers.AffineCipher=UselessParentheses
+com.thealgorithms.ciphers.DES=UselessParentheses
+com.thealgorithms.ciphers.ProductCipher=UselessMainMethod
+com.thealgorithms.ciphers.RSA=UselessParentheses
+com.thealgorithms.conversions.AnyBaseToAnyBase=UselessMainMethod,UselessParentheses
+com.thealgorithms.conversions.AnytoAny=UselessParentheses
+com.thealgorithms.conversions.RgbHsvConversion=UselessMainMethod
+com.thealgorithms.datastructures.crdt.Pair=UnusedPrivateField
+com.thealgorithms.datastructures.graphs.AStar=UselessParentheses
+com.thealgorithms.datastructures.graphs.AdjacencyMatrixGraph=CollapsibleIfStatements,UnnecessaryFullyQualifiedName,UselessParentheses
+com.thealgorithms.datastructures.graphs.BellmanFord=UselessMainMethod
+com.thealgorithms.datastructures.graphs.BipartiteGraphDFS=CollapsibleIfStatements
+com.thealgorithms.datastructures.graphs.ConnectedComponent=UselessMainMethod
+com.thealgorithms.datastructures.graphs.Cycles=UselessMainMethod
+com.thealgorithms.datastructures.graphs.Graphs=UselessMainMethod
+com.thealgorithms.datastructures.graphs.KahnsAlgorithm=UselessMainMethod
+com.thealgorithms.datastructures.graphs.MatrixGraphs=UselessMainMethod
+com.thealgorithms.datastructures.hashmap.hashing.HashMapCuckooHashing=UselessParentheses
+com.thealgorithms.datastructures.hashmap.hashing.MainCuckooHashing=UselessMainMethod
+com.thealgorithms.datastructures.heaps.FibonacciHeap=UselessParentheses
+com.thealgorithms.datastructures.heaps.HeapNode=UselessParentheses
+com.thealgorithms.datastructures.lists.DoublyLinkedList=UselessParentheses
+com.thealgorithms.datastructures.lists.Link=UselessMainMethod
+com.thealgorithms.datastructures.lists.RandomNode=UselessMainMethod
+com.thealgorithms.datastructures.lists.SearchSinglyLinkedListRecursion=UselessParentheses
+com.thealgorithms.datastructures.lists.SinglyLinkedList=UnusedLocalVariable,UselessMainMethod
+com.thealgorithms.datastructures.queues.Deque=UselessMainMethod
+com.thealgorithms.datastructures.queues.PriorityQueue=UselessParentheses
+com.thealgorithms.datastructures.trees.BSTRecursiveGeneric=UselessMainMethod
+com.thealgorithms.datastructures.trees.CheckBinaryTreeIsValidBST=UselessParentheses
+com.thealgorithms.datastructures.trees.LCA=UselessMainMethod
+com.thealgorithms.datastructures.trees.NearestRightKey=UselessMainMethod
+com.thealgorithms.datastructures.trees.PrintTopViewofTree=UselessMainMethod
+com.thealgorithms.datastructures.trees.SegmentTree=UselessParentheses
+com.thealgorithms.devutils.nodes.LargeTreeNode=UselessParentheses
+com.thealgorithms.devutils.nodes.SimpleNode=UselessParentheses
+com.thealgorithms.devutils.nodes.SimpleTreeNode=UselessParentheses
+com.thealgorithms.devutils.nodes.TreeNode=UselessParentheses
+com.thealgorithms.divideandconquer.ClosestPair=UnnecessaryFullyQualifiedName,UselessMainMethod,UselessParentheses
+com.thealgorithms.divideandconquer.Point=UselessParentheses
+com.thealgorithms.dynamicprogramming.CatalanNumber=UselessMainMethod
+com.thealgorithms.dynamicprogramming.EggDropping=UselessMainMethod
+com.thealgorithms.dynamicprogramming.LongestPalindromicSubsequence=UselessMainMethod
+com.thealgorithms.dynamicprogramming.WineProblem=UselessParentheses
+com.thealgorithms.maths.BinomialCoefficient=UselessParentheses
+com.thealgorithms.maths.Complex=UselessParentheses
+com.thealgorithms.maths.DistanceFormulaTest=UnnecessaryFullyQualifiedName
+com.thealgorithms.maths.EulerMethod=UselessMainMethod
+com.thealgorithms.maths.GCDRecursion=UselessMainMethod
+com.thealgorithms.maths.Gaussian=UselessParentheses
+com.thealgorithms.maths.GcdSolutionWrapper=UselessParentheses
+com.thealgorithms.maths.HeronsFormula=UselessParentheses
+com.thealgorithms.maths.JugglerSequence=UselessMainMethod
+com.thealgorithms.maths.KaprekarNumbers=UselessParentheses
+com.thealgorithms.maths.KeithNumber=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.LeonardoNumber=UselessParentheses
+com.thealgorithms.maths.LinearDiophantineEquationsSolver=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.MagicSquare=UselessMainMethod
+com.thealgorithms.maths.PiNilakantha=UselessMainMethod
+com.thealgorithms.maths.Prime.PrimeCheck=UselessMainMethod
+com.thealgorithms.maths.PythagoreanTriple=UselessMainMethod
+com.thealgorithms.maths.RomanNumeralUtil=UselessParentheses
+com.thealgorithms.maths.SecondMinMax=UselessParentheses
+com.thealgorithms.maths.SecondMinMaxTest=UnnecessaryFullyQualifiedName
+com.thealgorithms.maths.SimpsonIntegration=UselessMainMethod
+com.thealgorithms.maths.StandardDeviation=UselessParentheses
+com.thealgorithms.maths.SumOfArithmeticSeries=UselessParentheses
+com.thealgorithms.maths.TrinomialTriangle=UselessMainMethod,UselessParentheses
+com.thealgorithms.maths.VectorCrossProduct=UselessMainMethod
+com.thealgorithms.maths.Volume=UselessParentheses
+com.thealgorithms.matrix.RotateMatrixBy90Degrees=UselessMainMethod
+com.thealgorithms.misc.Sparsity=UselessParentheses
+com.thealgorithms.others.BankersAlgorithm=UselessMainMethod
+com.thealgorithms.others.BrianKernighanAlgorithm=UselessMainMethod
+com.thealgorithms.others.CRC16=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.CRC32=UselessMainMethod
+com.thealgorithms.others.Damm=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.others.Dijkstra=UselessMainMethod
+com.thealgorithms.others.GaussLegendre=UselessMainMethod
+com.thealgorithms.others.HappyNumbersSeq=UselessMainMethod
+com.thealgorithms.others.Huffman=UselessMainMethod
+com.thealgorithms.others.InsertDeleteInArray=UselessMainMethod
+com.thealgorithms.others.KochSnowflake=UselessMainMethod
+com.thealgorithms.others.Krishnamurthy=UselessMainMethod
+com.thealgorithms.others.LinearCongruentialGenerator=UselessMainMethod
+com.thealgorithms.others.Luhn=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.others.Mandelbrot=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.MiniMaxAlgorithm=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.MosAlgorithm=UselessMainMethod
+com.thealgorithms.others.PageRank=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.PerlinNoise=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.QueueUsingTwoStacks=UselessParentheses
+com.thealgorithms.others.Trieac=UselessMainMethod,UselessParentheses
+com.thealgorithms.others.Verhoeff=UnnecessaryFullyQualifiedName,UselessMainMethod
+com.thealgorithms.puzzlesandgames.Sudoku=UselessMainMethod
+com.thealgorithms.recursion.DiceThrower=UselessMainMethod
+com.thealgorithms.searches.HowManyTimesRotated=UselessMainMethod
+com.thealgorithms.searches.InterpolationSearch=UselessParentheses
+com.thealgorithms.searches.KMPSearch=UselessParentheses
+com.thealgorithms.searches.RabinKarpAlgorithm=UselessParentheses
+com.thealgorithms.searches.RecursiveBinarySearch=UselessMainMethod
+com.thealgorithms.sorts.BogoSort=UselessMainMethod
+com.thealgorithms.sorts.CircleSort=EmptyControlStatement
+com.thealgorithms.sorts.DutchNationalFlagSort=UselessParentheses
+com.thealgorithms.sorts.MergeSortNoExtraSpace=UselessParentheses
+com.thealgorithms.sorts.RadixSort=UselessParentheses
+com.thealgorithms.sorts.TreeSort=UselessMainMethod
+com.thealgorithms.sorts.WiggleSort=UselessParentheses
+com.thealgorithms.stacks.LargestRectangle=UselessMainMethod
+com.thealgorithms.stacks.MaximumMinimumWindow=UselessMainMethod
+com.thealgorithms.stacks.PostfixToInfix=UselessParentheses
+com.thealgorithms.strings.Alphabetical=UselessMainMethod
+com.thealgorithms.strings.HorspoolSearch=UnnecessaryFullyQualifiedName,UselessParentheses
+com.thealgorithms.strings.KMP=UselessMainMethod
+com.thealgorithms.strings.Lower=UselessMainMethod
+com.thealgorithms.strings.Palindrome=UselessParentheses
+com.thealgorithms.strings.Pangram=UselessMainMethod
+com.thealgorithms.strings.RabinKarp=UselessMainMethod
+com.thealgorithms.strings.Rotation=UselessMainMethod
+com.thealgorithms.strings.Upper=UselessMainMethod
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 000000000000..59a497427c0d
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,158 @@
+
+
+ 4.0.0
+ com.thealgorithms
+ Java
+ 1.0-SNAPSHOT
+ jar
+
+
+ UTF-8
+ 21
+ 21
+ 3.27.6
+
+
+
+
+
+ org.junit
+ junit-bom
+ 6.0.1
+ pom
+ import
+
+
+
+
+
+
+ org.junit.jupiter
+ junit-jupiter
+ test
+
+
+ org.assertj
+ assertj-core
+ ${assertj.version}
+ test
+
+
+ org.mockito
+ mockito-core
+ 5.21.0
+ test
+
+
+ org.apache.commons
+ commons-lang3
+ 3.20.0
+
+
+ org.apache.commons
+ commons-collections4
+ 4.5.0
+
+
+
+
+
+
+ maven-surefire-plugin
+ 3.5.4
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.14.1
+
+ 21
+
+ -Xlint:all
+ -Xlint:-auxiliaryclass
+ -Werror
+
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.14
+
+
+
+ prepare-agent
+
+
+
+ generate-code-coverage-report
+ test
+
+ report
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-checkstyle-plugin
+ 3.6.0
+
+ checkstyle.xml
+ true
+ true
+ warning
+
+
+
+ com.puppycrawl.tools
+ checkstyle
+ 12.3.1
+
+
+
+
+ com.github.spotbugs
+ spotbugs-maven-plugin
+ 4.9.8.2
+
+ spotbugs-exclude.xml
+ true
+
+
+ com.mebigfatguy.fb-contrib
+ fb-contrib
+ 7.7.2
+
+
+ com.h3xstream.findsecbugs
+ findsecbugs-plugin
+ 1.14.0
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-pmd-plugin
+ 3.28.0
+
+
+ /rulesets/java/maven-pmd-plugin-default.xml
+ /category/java/security.xml
+ file://${basedir}/pmd-custom_ruleset.xml
+
+ true
+ true
+ false
+ pmd-exclude.properties
+
+
+
+
+
\ No newline at end of file
diff --git a/spotbugs-exclude.xml b/spotbugs-exclude.xml
new file mode 100644
index 000000000000..3e2f1ff84ca8
--- /dev/null
+++ b/spotbugs-exclude.xml
@@ -0,0 +1,217 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java b/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java
new file mode 100644
index 000000000000..0dd23e937953
--- /dev/null
+++ b/src/main/java/com/thealgorithms/audiofilters/EMAFilter.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.audiofilters;
+
+/**
+ * Exponential Moving Average (EMA) Filter for smoothing audio signals.
+ *
+ * This filter applies an exponential moving average to a sequence of audio
+ * signal values, making it useful for smoothing out rapid fluctuations.
+ * The smoothing factor (alpha) controls the degree of smoothing.
+ *
+ *
Based on the definition from
+ * Wikipedia link.
+ */
+public class EMAFilter {
+ private final double alpha;
+ private double emaValue;
+ /**
+ * Constructs an EMA filter with a given smoothing factor.
+ *
+ * @param alpha Smoothing factor (0 < alpha <= 1)
+ * @throws IllegalArgumentException if alpha is not in (0, 1]
+ */
+ public EMAFilter(double alpha) {
+ if (alpha <= 0 || alpha > 1) {
+ throw new IllegalArgumentException("Alpha must be between 0 and 1.");
+ }
+ this.alpha = alpha;
+ this.emaValue = 0.0;
+ }
+ /**
+ * Applies the EMA filter to an audio signal array.
+ *
+ * @param audioSignal Array of audio samples to process
+ * @return Array of processed (smoothed) samples
+ */
+ public double[] apply(double[] audioSignal) {
+ if (audioSignal.length == 0) {
+ return new double[0];
+ }
+ double[] emaSignal = new double[audioSignal.length];
+ emaValue = audioSignal[0];
+ emaSignal[0] = emaValue;
+ for (int i = 1; i < audioSignal.length; i++) {
+ emaValue = alpha * audioSignal[i] + (1 - alpha) * emaValue;
+ emaSignal[i] = emaValue;
+ }
+ return emaSignal;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java b/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java
new file mode 100644
index 000000000000..fbc095909541
--- /dev/null
+++ b/src/main/java/com/thealgorithms/audiofilters/IIRFilter.java
@@ -0,0 +1,93 @@
+package com.thealgorithms.audiofilters;
+
+/**
+ * N-Order IIR Filter Assumes inputs are normalized to [-1, 1]
+ *
+ * Based on the difference equation from
+ * Wikipedia link
+ */
+public class IIRFilter {
+
+ private final int order;
+ private final double[] coeffsA;
+ private final double[] coeffsB;
+ private final double[] historyX;
+ private final double[] historyY;
+
+ /**
+ * Construct an IIR Filter
+ *
+ * @param order the filter's order
+ * @throws IllegalArgumentException if order is zero or less
+ */
+ public IIRFilter(int order) throws IllegalArgumentException {
+ if (order < 1) {
+ throw new IllegalArgumentException("order must be greater than zero");
+ }
+
+ this.order = order;
+ coeffsA = new double[order + 1];
+ coeffsB = new double[order + 1];
+
+ // Sane defaults
+ coeffsA[0] = 1.0;
+ coeffsB[0] = 1.0;
+
+ historyX = new double[order];
+ historyY = new double[order];
+ }
+
+ /**
+ * Set coefficients
+ *
+ * @param aCoeffs Denominator coefficients
+ * @param bCoeffs Numerator coefficients
+ * @throws IllegalArgumentException if {@code aCoeffs} or {@code bCoeffs} is
+ * not of size {@code order}, or if {@code aCoeffs[0]} is 0.0
+ */
+ public void setCoeffs(double[] aCoeffs, double[] bCoeffs) throws IllegalArgumentException {
+ if (aCoeffs.length != order) {
+ throw new IllegalArgumentException("aCoeffs must be of size " + order + ", got " + aCoeffs.length);
+ }
+
+ if (aCoeffs[0] == 0.0) {
+ throw new IllegalArgumentException("aCoeffs.get(0) must not be zero");
+ }
+
+ if (bCoeffs.length != order) {
+ throw new IllegalArgumentException("bCoeffs must be of size " + order + ", got " + bCoeffs.length);
+ }
+
+ for (int i = 0; i < order; i++) {
+ coeffsA[i] = aCoeffs[i];
+ coeffsB[i] = bCoeffs[i];
+ }
+ }
+
+ /**
+ * Process a single sample
+ *
+ * @param sample the sample to process
+ * @return the processed sample
+ */
+ public double process(double sample) {
+ double result = 0.0;
+
+ // Process
+ for (int i = 1; i <= order; i++) {
+ result += (coeffsB[i] * historyX[i - 1] - coeffsA[i] * historyY[i - 1]);
+ }
+ result = (result + coeffsB[0] * sample) / coeffsA[0];
+
+ // Feedback
+ for (int i = order - 1; i > 0; i--) {
+ historyX[i] = historyX[i - 1];
+ historyY[i] = historyY[i - 1];
+ }
+
+ historyX[0] = sample;
+ historyY[0] = result;
+
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
new file mode 100644
index 000000000000..c35a36d97a57
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/AllPathsFromSourceToTarget.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Program description - To find all possible paths from source to destination
+ * Wikipedia
+ *
+ * @author Siddhant Swarup Mallick
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class AllPathsFromSourceToTarget {
+
+ // No. of vertices in graph
+ private final int v;
+
+ // To store the paths from source to destination
+ static List> nm = new ArrayList<>();
+ // adjacency list
+ private ArrayList[] adjList;
+
+ // Constructor
+ public AllPathsFromSourceToTarget(int vertices) {
+
+ // initialise vertex count
+ this.v = vertices;
+
+ // initialise adjacency list
+ initAdjList();
+ }
+
+ // utility method to initialise adjacency list
+ private void initAdjList() {
+ adjList = new ArrayList[v];
+
+ for (int i = 0; i < v; i++) {
+ adjList[i] = new ArrayList<>();
+ }
+ }
+
+ // add edge from u to v
+ public void addEdge(int u, int v) {
+ // Add v to u's list.
+ adjList[u].add(v);
+ }
+
+ public void storeAllPaths(int s, int d) {
+ boolean[] isVisited = new boolean[v];
+ ArrayList pathList = new ArrayList<>();
+
+ // add source to path[]
+ pathList.add(s);
+ // Call recursive utility
+ storeAllPathsUtil(s, d, isVisited, pathList);
+ }
+
+ // A recursive function to print all paths from 'u' to 'd'.
+ // isVisited[] keeps track of vertices in current path.
+ // localPathList<> stores actual vertices in the current path
+ private void storeAllPathsUtil(Integer u, Integer d, boolean[] isVisited, List localPathList) {
+
+ if (u.equals(d)) {
+ nm.add(new ArrayList<>(localPathList));
+ return;
+ }
+
+ // Mark the current node
+ isVisited[u] = true;
+
+ // Recursion for all the vertices adjacent to current vertex
+
+ for (Integer i : adjList[u]) {
+ if (!isVisited[i]) {
+ // store current node in path[]
+ localPathList.add(i);
+ storeAllPathsUtil(i, d, isVisited, localPathList);
+
+ // remove current node in path[]
+ localPathList.remove(i);
+ }
+ }
+
+ // Mark the current node
+ isVisited[u] = false;
+ }
+
+ // Driver program
+ public static List> allPathsFromSourceToTarget(int vertices, int[][] a, int source, int destination) {
+ // Create a sample graph
+ AllPathsFromSourceToTarget g = new AllPathsFromSourceToTarget(vertices);
+ for (int[] i : a) {
+ g.addEdge(i[0], i[1]);
+ // edges are added
+ }
+ g.storeAllPaths(source, destination);
+ // method call to store all possible paths
+ return nm;
+ // returns all possible paths from source to destination
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
new file mode 100644
index 000000000000..f8cd0c40c20e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/ArrayCombination.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides methods to find all combinations of integers from 0 to n-1
+ * of a specified length k using backtracking.
+ */
+public final class ArrayCombination {
+ private ArrayCombination() {
+ }
+
+ /**
+ * Generates all possible combinations of length k from the integers 0 to n-1.
+ *
+ * @param n The total number of elements (0 to n-1).
+ * @param k The desired length of each combination.
+ * @return A list containing all combinations of length k.
+ * @throws IllegalArgumentException if n or k are negative, or if k is greater than n.
+ */
+ public static List> combination(int n, int k) {
+ if (n < 0 || k < 0 || k > n) {
+ throw new IllegalArgumentException("Invalid input: n must be non-negative, k must be non-negative and less than or equal to n.");
+ }
+
+ List> combinations = new ArrayList<>();
+ combine(combinations, new ArrayList<>(), 0, n, k);
+ return combinations;
+ }
+
+ /**
+ * A helper method that uses backtracking to find combinations.
+ *
+ * @param combinations The list to store all valid combinations found.
+ * @param current The current combination being built.
+ * @param start The starting index for the current recursion.
+ * @param n The total number of elements (0 to n-1).
+ * @param k The desired length of each combination.
+ */
+ private static void combine(List> combinations, List current, int start, int n, int k) {
+ // Base case: combination found
+ if (current.size() == k) {
+ combinations.add(new ArrayList<>(current));
+ return;
+ }
+
+ for (int i = start; i < n; i++) {
+ current.add(i);
+ combine(combinations, current, i + 1, n, k);
+ current.remove(current.size() - 1); // Backtrack
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/Combination.java b/src/main/java/com/thealgorithms/backtracking/Combination.java
new file mode 100644
index 000000000000..377d2c862d54
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/Combination.java
@@ -0,0 +1,66 @@
+package com.thealgorithms.backtracking;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.TreeSet;
+
+/**
+ * Finds all combinations of a given array using backtracking algorithm * @author Alan Piao (git-Alan Piao)
+ */
+public final class Combination {
+ private Combination() {
+ }
+
+ /**
+ * Find all combinations of given array using backtracking
+ * @param arr the array.
+ * @param n length of combination
+ * @param the type of elements in the array.
+ * @return a list of all combinations of length n. If n == 0, return null.
+ */
+ public static List> combination(T[] arr, int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("The combination length cannot be negative.");
+ }
+
+ if (n == 0) {
+ return Collections.emptyList();
+ }
+ T[] array = arr.clone();
+ Arrays.sort(array);
+
+ List> result = new LinkedList<>();
+ backtracking(array, n, 0, new TreeSet(), result);
+ return result;
+ }
+
+ /**
+ * Backtrack all possible combinations of a given array
+ * @param arr the array.
+ * @param n length of the combination
+ * @param index the starting index.
+ * @param currSet set that tracks current combination
+ * @param result the list contains all combination.
+ * @param the type of elements in the array.
+ */
+ private static void backtracking(T[] arr, int n, int index, TreeSet currSet, List> result) {
+ if (index + n - currSet.size() > arr.length) {
+ return;
+ }
+ if (currSet.size() == n - 1) {
+ for (int i = index; i < arr.length; i++) {
+ currSet.add(arr[i]);
+ result.add(new TreeSet<>(currSet));
+ currSet.remove(arr[i]);
+ }
+ return;
+ }
+ for (int i = index; i < arr.length; i++) {
+ currSet.add(arr[i]);
+ backtracking(arr, n, i + 1, currSet, result);
+ currSet.remove(arr[i]);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/CombinationSum.java b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java
new file mode 100644
index 000000000000..09b99032bdc1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/CombinationSum.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Backtracking: pick/not-pick with reuse of candidates. */
+public final class CombinationSum {
+ private CombinationSum() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List> combinationSum(int[] candidates, int target) {
+ List> results = new ArrayList<>();
+ if (candidates == null || candidates.length == 0) {
+ return results;
+ }
+
+ // Sort to help with pruning duplicates and early termination
+ Arrays.sort(candidates);
+ backtrack(candidates, target, 0, new ArrayList<>(), results);
+ return results;
+ }
+
+ private static void backtrack(int[] candidates, int remaining, int start, List combination, List> results) {
+ if (remaining == 0) {
+ // Found valid combination; add a copy
+ results.add(new ArrayList<>(combination));
+ return;
+ }
+
+ for (int i = start; i < candidates.length; i++) {
+ int candidate = candidates[i];
+
+ // If candidate is greater than remaining target, further candidates (sorted) will also be too big
+ if (candidate > remaining) {
+ break;
+ }
+
+ // include candidate
+ combination.add(candidate);
+ // Because we can reuse the same element, we pass i (not i + 1)
+ backtrack(candidates, remaining - candidate, i, combination, results);
+ // backtrack: remove last
+ combination.remove(combination.size() - 1);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
new file mode 100644
index 000000000000..6bfb026c7de9
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/CrosswordSolver.java
@@ -0,0 +1,125 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * A class to solve a crossword puzzle using backtracking.
+ * Example:
+ * Input:
+ * puzzle = {
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '},
+ * {' ', ' ', ' '}
+ * }
+ * words = List.of("cat", "dog")
+ *
+ * Output:
+ * {
+ * {'c', 'a', 't'},
+ * {' ', ' ', ' '},
+ * {'d', 'o', 'g'}
+ * }
+ */
+public final class CrosswordSolver {
+ private CrosswordSolver() {
+ }
+
+ /**
+ * Checks if a word can be placed at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word might be placed.
+ * @param col The column index where the word might be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ * @return true if the word can be placed, false otherwise.
+ */
+ public static boolean isValid(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ if (row + i >= puzzle.length || puzzle[row + i][col] != ' ') {
+ return false;
+ }
+ } else {
+ if (col + i >= puzzle[0].length || puzzle[row][col + i] != ' ') {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Places a word at the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be placed.
+ * @param row The row index where the word will be placed.
+ * @param col The column index where the word will be placed.
+ * @param vertical If true, the word is placed vertically; otherwise, horizontally.
+ */
+ public static void placeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = word.charAt(i);
+ } else {
+ puzzle[row][col + i] = word.charAt(i);
+ }
+ }
+ }
+
+ /**
+ * Removes a word from the specified position in the crossword.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param word The word to be removed.
+ * @param row The row index where the word is placed.
+ * @param col The column index where the word is placed.
+ * @param vertical If true, the word was placed vertically; otherwise, horizontally.
+ */
+ public static void removeWord(char[][] puzzle, String word, int row, int col, boolean vertical) {
+ for (int i = 0; i < word.length(); i++) {
+ if (vertical) {
+ puzzle[row + i][col] = ' ';
+ } else {
+ puzzle[row][col + i] = ' ';
+ }
+ }
+ }
+
+ /**
+ * Solves the crossword puzzle using backtracking.
+ *
+ * @param puzzle The crossword puzzle represented as a 2D char array.
+ * @param words The list of words to be placed.
+ * @return true if the crossword is solved, false otherwise.
+ */
+ public static boolean solveCrossword(char[][] puzzle, Collection words) {
+ // Create a mutable copy of the words list
+ List remainingWords = new ArrayList<>(words);
+
+ for (int row = 0; row < puzzle.length; row++) {
+ for (int col = 0; col < puzzle[0].length; col++) {
+ if (puzzle[row][col] == ' ') {
+ for (String word : new ArrayList<>(remainingWords)) {
+ for (boolean vertical : new boolean[] {true, false}) {
+ if (isValid(puzzle, word, row, col, vertical)) {
+ placeWord(puzzle, word, row, col, vertical);
+ remainingWords.remove(word);
+ if (solveCrossword(puzzle, remainingWords)) {
+ return true;
+ }
+ remainingWords.add(word);
+ removeWord(puzzle, word, row, col, vertical);
+ }
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/FloodFill.java b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
new file mode 100644
index 000000000000..0f31a9c5a30e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/FloodFill.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Java program for Flood fill algorithm.
+ * @author Akshay Dubey (Git-Akshay Dubey)
+ */
+public final class FloodFill {
+ private FloodFill() {
+ }
+
+ /**
+ * Get the color at the given coordinates of a 2D image
+ *
+ * @param image The image to be filled
+ * @param x The x coordinate of which color is to be obtained
+ * @param y The y coordinate of which color is to be obtained
+ */
+
+ public static int getPixel(final int[][] image, final int x, final int y) {
+ return image[x][y];
+ }
+
+ /**
+ * Put the color at the given coordinates of a 2D image
+ *
+ * @param image The image to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
+ */
+ public static void putPixel(final int[][] image, final int x, final int y, final int newColor) {
+ image[x][y] = newColor;
+ }
+
+ /**
+ * Fill the 2D image with new color
+ *
+ * @param image The image to be filled
+ * @param x The x coordinate at which color is to be filled
+ * @param y The y coordinate at which color is to be filled
+ * @param newColor The new color which to be filled in the image
+ * @param oldColor The old color which is to be replaced in the image
+ */
+ public static void floodFill(final int[][] image, final int x, final int y, final int newColor, final int oldColor) {
+ if (newColor == oldColor || x < 0 || x >= image.length || y < 0 || y >= image[x].length || getPixel(image, x, y) != oldColor) {
+ return;
+ }
+
+ putPixel(image, x, y, newColor);
+
+ /* Recursively check for horizontally & vertically adjacent coordinates */
+ floodFill(image, x + 1, y, newColor, oldColor);
+ floodFill(image, x - 1, y, newColor, oldColor);
+ floodFill(image, x, y + 1, newColor, oldColor);
+ floodFill(image, x, y - 1, newColor, oldColor);
+
+ /* Recursively check for diagonally adjacent coordinates */
+ floodFill(image, x + 1, y - 1, newColor, oldColor);
+ floodFill(image, x - 1, y + 1, newColor, oldColor);
+ floodFill(image, x + 1, y + 1, newColor, oldColor);
+ floodFill(image, x - 1, y - 1, newColor, oldColor);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/KnightsTour.java b/src/main/java/com/thealgorithms/backtracking/KnightsTour.java
new file mode 100644
index 000000000000..2c2da659f3aa
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/KnightsTour.java
@@ -0,0 +1,156 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+
+/**
+ * The KnightsTour class solves the Knight's Tour problem using backtracking.
+ *
+ * Problem Statement:
+ * Given an N*N board with a knight placed on the first block, the knight must
+ * move according to chess rules and visit each square on the board exactly once.
+ * The class outputs the sequence of moves for the knight.
+ *
+ * Example:
+ * Input: N = 8 (8x8 chess board)
+ * Output: The sequence of numbers representing the order in which the knight visits each square.
+ */
+public final class KnightsTour {
+ private KnightsTour() {
+ }
+
+ // The size of the chess board (12x12 grid, with 2 extra rows/columns as a buffer around a 8x8 area)
+ private static final int BASE = 12;
+
+ // Possible moves for a knight in chess
+ private static final int[][] MOVES = {
+ {1, -2},
+ {2, -1},
+ {2, 1},
+ {1, 2},
+ {-1, 2},
+ {-2, 1},
+ {-2, -1},
+ {-1, -2},
+ };
+
+ // Chess grid representing the board
+ static int[][] grid;
+
+ // Total number of cells the knight needs to visit
+ static int total;
+
+ /**
+ * Resets the chess board to its initial state.
+ * Initializes the grid with boundary cells marked as -1 and internal cells as 0.
+ * Sets the total number of cells the knight needs to visit.
+ */
+ public static void resetBoard() {
+ grid = new int[BASE][BASE];
+ total = (BASE - 4) * (BASE - 4);
+ for (int r = 0; r < BASE; r++) {
+ for (int c = 0; c < BASE; c++) {
+ if (r < 2 || r > BASE - 3 || c < 2 || c > BASE - 3) {
+ grid[r][c] = -1; // Mark boundary cells
+ }
+ }
+ }
+ }
+
+ /**
+ * Recursive method to solve the Knight's Tour problem.
+ *
+ * @param row The current row of the knight
+ * @param column The current column of the knight
+ * @param count The current move number
+ * @return True if a solution is found, False otherwise
+ */
+ static boolean solve(int row, int column, int count) {
+ if (count > total) {
+ return true;
+ }
+
+ List neighbor = neighbors(row, column);
+
+ if (neighbor.isEmpty() && count != total) {
+ return false;
+ }
+
+ // Sort neighbors by Warnsdorff's rule (fewest onward moves)
+ neighbor.sort(Comparator.comparingInt(a -> a[2]));
+
+ for (int[] nb : neighbor) {
+ int nextRow = nb[0];
+ int nextCol = nb[1];
+ grid[nextRow][nextCol] = count;
+ if (!orphanDetected(count, nextRow, nextCol) && solve(nextRow, nextCol, count + 1)) {
+ return true;
+ }
+ grid[nextRow][nextCol] = 0; // Backtrack
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a list of valid neighboring cells where the knight can move.
+ *
+ * @param row The current row of the knight
+ * @param column The current column of the knight
+ * @return A list of arrays representing valid moves, where each array contains:
+ * {nextRow, nextCol, numberOfPossibleNextMoves}
+ */
+ static List neighbors(int row, int column) {
+ List neighbour = new ArrayList<>();
+
+ for (int[] m : MOVES) {
+ int x = m[0];
+ int y = m[1];
+ if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
+ int num = countNeighbors(row + y, column + x);
+ neighbour.add(new int[] {row + y, column + x, num});
+ }
+ }
+ return neighbour;
+ }
+
+ /**
+ * Counts the number of possible valid moves for a knight from a given position.
+ *
+ * @param row The row of the current position
+ * @param column The column of the current position
+ * @return The number of valid neighboring moves
+ */
+ static int countNeighbors(int row, int column) {
+ int num = 0;
+ for (int[] m : MOVES) {
+ int x = m[0];
+ int y = m[1];
+ if (row + y >= 0 && row + y < BASE && column + x >= 0 && column + x < BASE && grid[row + y][column + x] == 0) {
+ num++;
+ }
+ }
+ return num;
+ }
+
+ /**
+ * Detects if moving to a given position will create an orphan (a position with no further valid moves).
+ *
+ * @param count The current move number
+ * @param row The row of the current position
+ * @param column The column of the current position
+ * @return True if an orphan is detected, False otherwise
+ */
+ static boolean orphanDetected(int count, int row, int column) {
+ if (count < total - 1) {
+ List neighbor = neighbors(row, column);
+ for (int[] nb : neighbor) {
+ if (countNeighbors(nb[0], nb[1]) == 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/MColoring.java b/src/main/java/com/thealgorithms/backtracking/MColoring.java
new file mode 100644
index 000000000000..d0188dfd13aa
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/MColoring.java
@@ -0,0 +1,96 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+
+/**
+ * Node class represents a graph node. Each node is associated with a color
+ * (initially 1) and contains a set of edges representing its adjacent nodes.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+class Node {
+ int color = 1; // Initial color for each node
+ Set edges = new HashSet(); // Set of edges representing adjacent nodes
+}
+
+/**
+ * MColoring class solves the M-Coloring problem where the goal is to determine
+ * if it's possible to color a graph using at most M colors such that no two
+ * adjacent nodes have the same color.
+ */
+public final class MColoring {
+
+ private MColoring() {
+ } // Prevent instantiation of utility class
+
+ /**
+ * Determines whether it is possible to color the graph using at most M colors.
+ *
+ * @param nodes List of nodes representing the graph.
+ * @param n The total number of nodes in the graph.
+ * @param m The maximum number of allowed colors.
+ * @return true if the graph can be colored using M colors, false otherwise.
+ */
+ static boolean isColoringPossible(ArrayList nodes, int n, int m) {
+
+ // Visited array keeps track of whether each node has been processed.
+ ArrayList visited = new ArrayList();
+ for (int i = 0; i < n + 1; i++) {
+ visited.add(0); // Initialize all nodes as unvisited (0)
+ }
+
+ // The number of colors used so far (initially set to 1, since all nodes
+ // start with color 1).
+ int maxColors = 1;
+
+ // Loop through all the nodes to ensure every node is visited, in case the
+ // graph is disconnected.
+ for (int sv = 1; sv <= n; sv++) {
+ if (visited.get(sv) > 0) {
+ continue; // Skip nodes that are already visited
+ }
+
+ // If the node is unvisited, mark it as visited and add it to the queue for BFS.
+ visited.set(sv, 1);
+ Queue q = new LinkedList<>();
+ q.add(sv);
+
+ // Perform BFS to process all nodes and their adjacent nodes
+ while (q.size() != 0) {
+ int top = q.peek(); // Get the current node from the queue
+ q.remove();
+
+ // Check all adjacent nodes of the current node
+ for (int it : nodes.get(top).edges) {
+
+ // If the adjacent node has the same color as the current node, increment its
+ // color to avoid conflict.
+ if (nodes.get(top).color == nodes.get(it).color) {
+ nodes.get(it).color += 1;
+ }
+
+ // Keep track of the maximum number of colors used so far
+ maxColors = Math.max(maxColors, Math.max(nodes.get(top).color, nodes.get(it).color));
+
+ // If the number of colors used exceeds the allowed limit M, return false.
+ if (maxColors > m) {
+ return false;
+ }
+
+ // If the adjacent node hasn't been visited yet, mark it as visited and add it
+ // to the queue for further processing.
+ if (visited.get(it) == 0) {
+ visited.set(it, 1);
+ q.add(it);
+ }
+ }
+ }
+ }
+
+ return true; // Possible to color the entire graph with M or fewer colors.
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
new file mode 100644
index 000000000000..8247172e7ee0
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/MazeRecursion.java
@@ -0,0 +1,125 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * This class contains methods to solve a maze using recursive backtracking.
+ * The maze is represented as a 2D array where walls, paths, and visited/dead
+ * ends are marked with different integers.
+ *
+ * The goal is to find a path from a starting position to the target position
+ * (map[6][5]) while navigating through the maze.
+ */
+public final class MazeRecursion {
+
+ private MazeRecursion() {
+ }
+
+ /**
+ * This method solves the maze using the "down -> right -> up -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingFirstStrategy(int[][] map) {
+ if (setWay(map, 1, 1)) {
+ return map;
+ }
+ return null;
+ }
+
+ /**
+ * This method solves the maze using the "up -> right -> down -> left"
+ * movement strategy.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @return The solved maze with paths marked, or null if no solution exists.
+ */
+ public static int[][] solveMazeUsingSecondStrategy(int[][] map) {
+ if (setWay2(map, 1, 1)) {
+ return map;
+ }
+ return null;
+ }
+
+ /**
+ * Attempts to find a path through the maze using a "down -> right -> up -> left"
+ * movement strategy. The path is marked with '2' for valid paths and '3' for dead ends.
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
+ */
+ private static boolean setWay(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
+ return true;
+ }
+
+ // If the current position is unvisited (0), explore it
+ if (map[i][j] == 0) {
+ // Mark the current position as '2'
+ map[i][j] = 2;
+
+ // Move down
+ if (setWay(map, i + 1, j)) {
+ return true;
+ }
+ // Move right
+ else if (setWay(map, i, j + 1)) {
+ return true;
+ }
+ // Move up
+ else if (setWay(map, i - 1, j)) {
+ return true;
+ }
+ // Move left
+ else if (setWay(map, i, j - 1)) {
+ return true;
+ }
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
+ return false;
+ }
+ return false;
+ }
+
+ /**
+ * Attempts to find a path through the maze using an alternative movement
+ * strategy "up -> right -> down -> left".
+ *
+ * @param map The 2D array representing the maze (walls, paths, etc.)
+ * @param i The current x-coordinate of the ball (row index)
+ * @param j The current y-coordinate of the ball (column index)
+ * @return True if a path is found to (6,5), otherwise false
+ */
+ private static boolean setWay2(int[][] map, int i, int j) {
+ if (map[6][5] == 2) {
+ return true;
+ }
+
+ if (map[i][j] == 0) {
+ map[i][j] = 2;
+
+ // Move up
+ if (setWay2(map, i - 1, j)) {
+ return true;
+ }
+ // Move right
+ else if (setWay2(map, i, j + 1)) {
+ return true;
+ }
+ // Move down
+ else if (setWay2(map, i + 1, j)) {
+ return true;
+ }
+ // Move left
+ else if (setWay2(map, i, j - 1)) {
+ return true;
+ }
+
+ map[i][j] = 3; // Mark as dead end (3) if no direction worked
+ return false;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/NQueens.java b/src/main/java/com/thealgorithms/backtracking/NQueens.java
new file mode 100644
index 000000000000..1a8e453e34cb
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/NQueens.java
@@ -0,0 +1,111 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Problem statement: Given a N x N chess board. Return all arrangements in
+ * which N queens can be placed on the board such no two queens attack each
+ * other. Ex. N = 6 Solution= There are 4 possible ways Arrangement: 1 ".Q....",
+ * "...Q..", ".....Q", "Q.....", "..Q...", "....Q."
+ *
+ * Arrangement: 2 "..Q...", ".....Q", ".Q....", "....Q.", "Q.....", "...Q.."
+ *
+ * Arrangement: 3 "...Q..", "Q.....", "....Q.", ".Q....", ".....Q", "..Q..."
+ *
+ * Arrangement: 4 "....Q.", "..Q...", "Q.....", ".....Q", "...Q..", ".Q...."
+ *
+ * Solution: Brute Force approach:
+ *
+ * Generate all possible arrangement to place N queens on N*N board. Check each
+ * board if queens are placed safely. If it is safe, include arrangement in
+ * solution set. Otherwise, ignore it
+ *
+ * Optimized solution: This can be solved using backtracking in below steps
+ *
+ * Start with first column and place queen on first row Try placing queen in a
+ * row on second column If placing second queen in second column attacks any of
+ * the previous queens, change the row in second column otherwise move to next
+ * column and try to place next queen In case if there is no rows where a queen
+ * can be placed such that it doesn't attack previous queens, then go back to
+ * previous column and change row of previous queen. Keep doing this until last
+ * queen is not placed safely. If there is no such way then return an empty list
+ * as solution
+ */
+public final class NQueens {
+ private NQueens() {
+ }
+
+ public static List> getNQueensArrangements(int queens) {
+ List> arrangements = new ArrayList<>();
+ getSolution(queens, arrangements, new int[queens], 0);
+ return arrangements;
+ }
+
+ public static void placeQueens(final int queens) {
+ List> arrangements = new ArrayList>();
+ getSolution(queens, arrangements, new int[queens], 0);
+ if (arrangements.isEmpty()) {
+ System.out.println("There is no way to place " + queens + " queens on board of size " + queens + "x" + queens);
+ } else {
+ System.out.println("Arrangement for placing " + queens + " queens");
+ }
+ for (List arrangement : arrangements) {
+ arrangement.forEach(System.out::println);
+ System.out.println();
+ }
+ }
+
+ /**
+ * This is backtracking function which tries to place queen recursively
+ *
+ * @param boardSize: size of chess board
+ * @param solutions: this holds all possible arrangements
+ * @param columns: columns[i] = rowId where queen is placed in ith column.
+ * @param columnIndex: This is the column in which queen is being placed
+ */
+ private static void getSolution(int boardSize, List> solutions, int[] columns, int columnIndex) {
+ if (columnIndex == boardSize) {
+ // this means that all queens have been placed
+ List sol = new ArrayList();
+ for (int i = 0; i < boardSize; i++) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < boardSize; j++) {
+ sb.append(j == columns[i] ? "Q" : ".");
+ }
+ sol.add(sb.toString());
+ }
+ solutions.add(sol);
+ return;
+ }
+
+ // This loop tries to place queen in a row one by one
+ for (int rowIndex = 0; rowIndex < boardSize; rowIndex++) {
+ columns[columnIndex] = rowIndex;
+ if (isPlacedCorrectly(columns, rowIndex, columnIndex)) {
+ // If queen is placed successfully at rowIndex in column=columnIndex then try
+ // placing queen in next column
+ getSolution(boardSize, solutions, columns, columnIndex + 1);
+ }
+ }
+ }
+
+ /**
+ * This function checks if queen can be placed at row = rowIndex in column =
+ * columnIndex safely
+ *
+ * @param columns: columns[i] = rowId where queen is placed in ith column.
+ * @param rowIndex: row in which queen has to be placed
+ * @param columnIndex: column in which queen is being placed
+ * @return true: if queen can be placed safely false: otherwise
+ */
+ private static boolean isPlacedCorrectly(int[] columns, int rowIndex, int columnIndex) {
+ for (int i = 0; i < columnIndex; i++) {
+ int diff = Math.abs(columns[i] - rowIndex);
+ if (diff == 0 || columnIndex - i == diff) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java b/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java
new file mode 100644
index 000000000000..bf93f946ab7b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/ParenthesesGenerator.java
@@ -0,0 +1,50 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class generates all valid combinations of parentheses for a given number of pairs using backtracking.
+ */
+public final class ParenthesesGenerator {
+ private ParenthesesGenerator() {
+ }
+
+ /**
+ * Generates all valid combinations of parentheses for a given number of pairs.
+ *
+ * @param n The number of pairs of parentheses.
+ * @return A list of strings representing valid combinations of parentheses.
+ * @throws IllegalArgumentException if n is less than 0.
+ */
+ public static List generateParentheses(final int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("The number of pairs of parentheses cannot be negative");
+ }
+ List result = new ArrayList<>();
+ generateParenthesesHelper(result, "", 0, 0, n);
+ return result;
+ }
+
+ /**
+ * Helper function for generating all valid combinations of parentheses recursively.
+ *
+ * @param result The list to store valid combinations.
+ * @param current The current combination being formed.
+ * @param open The number of open parentheses.
+ * @param close The number of closed parentheses.
+ * @param n The total number of pairs of parentheses.
+ */
+ private static void generateParenthesesHelper(List result, final String current, final int open, final int close, final int n) {
+ if (current.length() == n * 2) {
+ result.add(current);
+ return;
+ }
+ if (open < n) {
+ generateParenthesesHelper(result, current + "(", open + 1, close, n);
+ }
+ if (close < open) {
+ generateParenthesesHelper(result, current + ")", open, close + 1, n);
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/Permutation.java b/src/main/java/com/thealgorithms/backtracking/Permutation.java
new file mode 100644
index 000000000000..21d26e53980f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/Permutation.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.backtracking;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Finds all permutations of given array
+ * @author Alan Piao (Git-Alan Piao)
+ */
+public final class Permutation {
+ private Permutation() {
+ }
+
+ /**
+ * Find all permutations of given array using backtracking
+ * @param arr the array.
+ * @param the type of elements in the array.
+ * @return a list of all permutations.
+ */
+ public static List permutation(T[] arr) {
+ T[] array = arr.clone();
+ List result = new LinkedList<>();
+ backtracking(array, 0, result);
+ return result;
+ }
+
+ /**
+ * Backtrack all possible orders of a given array
+ * @param arr the array.
+ * @param index the starting index.
+ * @param result the list contains all permutations.
+ * @param the type of elements in the array.
+ */
+ private static void backtracking(T[] arr, int index, List result) {
+ if (index == arr.length) {
+ result.add(arr.clone());
+ }
+ for (int i = index; i < arr.length; i++) {
+ swap(index, i, arr);
+ backtracking(arr, index + 1, result);
+ swap(index, i, arr);
+ }
+ }
+
+ /**
+ * Swap two element for a given array
+ * @param a first index
+ * @param b second index
+ * @param arr the array.
+ * @param the type of elements in the array.
+ */
+ private static void swap(int a, int b, T[] arr) {
+ T temp = arr[a];
+ arr[a] = arr[b];
+ arr[b] = temp;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/PowerSum.java b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
new file mode 100644
index 000000000000..b34ba660ebd7
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/PowerSum.java
@@ -0,0 +1,51 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Problem Statement:
+ * Find the number of ways that a given integer, N, can be expressed as the sum of the Xth powers
+ * of unique, natural numbers.
+ * For example, if N=100 and X=3, we have to find all combinations of unique cubes adding up to 100.
+ * The only solution is 1^3 + 2^3 + 3^3 + 4^3. Therefore, the output will be 1.
+ *
+ * N is represented by the parameter 'targetSum' in the code.
+ * X is represented by the parameter 'power' in the code.
+ */
+public class PowerSum {
+
+ /**
+ * Calculates the number of ways to express the target sum as a sum of Xth powers of unique natural numbers.
+ *
+ * @param targetSum The target sum to achieve (N in the problem statement)
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @return The number of ways to express the target sum
+ */
+ public int powSum(int targetSum, int power) {
+ // Special case: when both targetSum and power are zero
+ if (targetSum == 0 && power == 0) {
+ return 1; // by convention, one way to sum to zero: use nothing
+ }
+ return sumRecursive(targetSum, power, 1, 0);
+ }
+
+ /**
+ * Recursively calculates the number of ways to express the remaining sum as a sum of Xth powers.
+ *
+ * @param remainingSum The remaining sum to achieve
+ * @param power The power to raise natural numbers to (X in the problem statement)
+ * @param currentNumber The current natural number being considered
+ * @param currentSum The current sum of powered numbers
+ * @return The number of valid combinations
+ */
+ private int sumRecursive(int remainingSum, int power, int currentNumber, int currentSum) {
+ int newSum = currentSum + (int) Math.pow(currentNumber, power);
+
+ if (newSum == remainingSum) {
+ return 1;
+ }
+ if (newSum > remainingSum) {
+ return 0;
+ }
+
+ return sumRecursive(remainingSum, power, currentNumber + 1, newSum) + sumRecursive(remainingSum, power, currentNumber + 1, currentSum);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java b/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java
new file mode 100644
index 000000000000..4a159dbfe0b1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/SubsequenceFinder.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Class generates all subsequences for a given list of elements using backtracking
+ */
+public final class SubsequenceFinder {
+ private SubsequenceFinder() {
+ }
+
+ /**
+ * Find all subsequences of given list using backtracking
+ *
+ * @param sequence a list of items on the basis of which we need to generate all subsequences
+ * @param the type of elements in the array
+ * @return a list of all subsequences
+ */
+ public static List> generateAll(List sequence) {
+ List> allSubSequences = new ArrayList<>();
+ if (sequence.isEmpty()) {
+ allSubSequences.add(new ArrayList<>());
+ return allSubSequences;
+ }
+ List currentSubsequence = new ArrayList<>();
+ backtrack(sequence, currentSubsequence, 0, allSubSequences);
+ return allSubSequences;
+ }
+
+ /**
+ * Iterate through each branch of states
+ * We know that each state has exactly two branching
+ * It terminates when it reaches the end of the given sequence
+ *
+ * @param sequence all elements
+ * @param currentSubsequence current subsequence
+ * @param index current index
+ * @param allSubSequences contains all sequences
+ * @param the type of elements which we generate
+ */
+ private static void backtrack(List sequence, List currentSubsequence, final int index, List> allSubSequences) {
+ assert index <= sequence.size();
+ if (index == sequence.size()) {
+ allSubSequences.add(new ArrayList<>(currentSubsequence));
+ return;
+ }
+
+ backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+ currentSubsequence.add(sequence.get(index));
+ backtrack(sequence, currentSubsequence, index + 1, allSubSequences);
+ currentSubsequence.removeLast();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
new file mode 100644
index 000000000000..543fe2d02b50
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/SudokuSolver.java
@@ -0,0 +1,157 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Sudoku Solver using Backtracking Algorithm
+ * Solves a 9x9 Sudoku puzzle by filling empty cells with valid digits (1-9)
+ *
+ * @author Navadeep0007
+ */
+public final class SudokuSolver {
+
+ private static final int GRID_SIZE = 9;
+ private static final int SUBGRID_SIZE = 3;
+ private static final int EMPTY_CELL = 0;
+
+ private SudokuSolver() {
+ // Utility class, prevent instantiation
+ }
+
+ /**
+ * Solves the Sudoku puzzle using backtracking
+ *
+ * @param board 9x9 Sudoku board with 0 representing empty cells
+ * @return true if puzzle is solved, false otherwise
+ */
+ public static boolean solveSudoku(int[][] board) {
+ if (board == null || board.length != GRID_SIZE) {
+ return false;
+ }
+
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row].length != GRID_SIZE) {
+ return false;
+ }
+ }
+
+ return solve(board);
+ }
+
+ /**
+ * Recursive helper method to solve the Sudoku puzzle
+ *
+ * @param board the Sudoku board
+ * @return true if solution is found, false otherwise
+ */
+ private static boolean solve(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == EMPTY_CELL) {
+ for (int number = 1; number <= GRID_SIZE; number++) {
+ if (isValidPlacement(board, row, col, number)) {
+ board[row][col] = number;
+
+ if (solve(board)) {
+ return true;
+ }
+
+ // Backtrack
+ board[row][col] = EMPTY_CELL;
+ }
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Checks if placing a number at given position is valid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to place (1-9)
+ * @return true if placement is valid, false otherwise
+ */
+ private static boolean isValidPlacement(int[][] board, int row, int col, int number) {
+ return !isNumberInRow(board, row, number) && !isNumberInColumn(board, col, number) && !isNumberInSubgrid(board, row, col, number);
+ }
+
+ /**
+ * Checks if number exists in the given row
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param number number to check
+ * @return true if number exists in row, false otherwise
+ */
+ private static boolean isNumberInRow(int[][] board, int row, int number) {
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the given column
+ *
+ * @param board the Sudoku board
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in column, false otherwise
+ */
+ private static boolean isNumberInColumn(int[][] board, int col, int number) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (board[row][col] == number) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Checks if number exists in the 3x3 subgrid
+ *
+ * @param board the Sudoku board
+ * @param row row index
+ * @param col column index
+ * @param number number to check
+ * @return true if number exists in subgrid, false otherwise
+ */
+ private static boolean isNumberInSubgrid(int[][] board, int row, int col, int number) {
+ int subgridRowStart = row - row % SUBGRID_SIZE;
+ int subgridColStart = col - col % SUBGRID_SIZE;
+
+ for (int i = subgridRowStart; i < subgridRowStart + SUBGRID_SIZE; i++) {
+ for (int j = subgridColStart; j < subgridColStart + SUBGRID_SIZE; j++) {
+ if (board[i][j] == number) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Prints the Sudoku board
+ *
+ * @param board the Sudoku board
+ */
+ public static void printBoard(int[][] board) {
+ for (int row = 0; row < GRID_SIZE; row++) {
+ if (row % SUBGRID_SIZE == 0 && row != 0) {
+ System.out.println("-----------");
+ }
+ for (int col = 0; col < GRID_SIZE; col++) {
+ if (col % SUBGRID_SIZE == 0 && col != 0) {
+ System.out.print("|");
+ }
+ System.out.print(board[row][col]);
+ }
+ System.out.println();
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
new file mode 100644
index 000000000000..4804e247ab03
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/UniquePermutation.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.backtracking;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Generates all UNIQUE permutations of a string, even when duplicate characters exist.
+ *
+ * Example:
+ * Input: "AAB"
+ * Output: ["AAB", "ABA", "BAA"]
+ *
+ * Time Complexity: O(n! * n)
+ */
+public final class UniquePermutation {
+
+ private UniquePermutation() {
+ // Prevent instantiation
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ public static List generateUniquePermutations(String input) {
+ List result = new ArrayList<>();
+ if (input == null) {
+ return result;
+ }
+
+ char[] chars = input.toCharArray();
+ Arrays.sort(chars); // important: sort to detect duplicates
+
+ backtrack(chars, new boolean[chars.length], new StringBuilder(), result);
+ return result;
+ }
+
+ private static void backtrack(char[] chars, boolean[] used, StringBuilder current, List result) {
+
+ if (current.length() == chars.length) {
+ result.add(current.toString());
+ return;
+ }
+
+ for (int i = 0; i < chars.length; i++) {
+
+ // skip duplicates
+ if (i > 0 && chars[i] == chars[i - 1] && !used[i - 1]) {
+ continue;
+ }
+
+ if (!used[i]) {
+ used[i] = true;
+ current.append(chars[i]);
+
+ backtrack(chars, used, current, result);
+
+ // undo changes
+ used[i] = false;
+ current.deleteCharAt(current.length() - 1);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
new file mode 100644
index 000000000000..1854cab20a7f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/WordPatternMatcher.java
@@ -0,0 +1,86 @@
+package com.thealgorithms.backtracking;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Class to determine if a pattern matches a string using backtracking.
+ *
+ * Example:
+ * Pattern: "abab"
+ * Input String: "JavaPythonJavaPython"
+ * Output: true
+ *
+ * Pattern: "aaaa"
+ * Input String: "JavaJavaJavaJava"
+ * Output: true
+ *
+ * Pattern: "aabb"
+ * Input String: "JavaPythonPythonJava"
+ * Output: false
+ */
+public final class WordPatternMatcher {
+ private WordPatternMatcher() {
+ }
+
+ /**
+ * Determines if the given pattern matches the input string using backtracking.
+ *
+ * @param pattern The pattern to match.
+ * @param inputString The string to match against the pattern.
+ * @return True if the pattern matches the string, False otherwise.
+ */
+ public static boolean matchWordPattern(String pattern, String inputString) {
+ Map patternMap = new HashMap<>();
+ Map strMap = new HashMap<>();
+ return backtrack(pattern, inputString, 0, 0, patternMap, strMap);
+ }
+
+ /**
+ * Backtracking helper function to check if the pattern matches the string.
+ *
+ * @param pattern The pattern string.
+ * @param inputString The string to match against the pattern.
+ * @param patternIndex Current index in the pattern.
+ * @param strIndex Current index in the input string.
+ * @param patternMap Map to store pattern characters to string mappings.
+ * @param strMap Map to store string to pattern character mappings.
+ * @return True if the pattern matches, False otherwise.
+ */
+ private static boolean backtrack(String pattern, String inputString, int patternIndex, int strIndex, Map patternMap, Map strMap) {
+ if (patternIndex == pattern.length() && strIndex == inputString.length()) {
+ return true;
+ }
+ if (patternIndex == pattern.length() || strIndex == inputString.length()) {
+ return false;
+ }
+
+ char currentChar = pattern.charAt(patternIndex);
+ if (patternMap.containsKey(currentChar)) {
+ String mappedStr = patternMap.get(currentChar);
+ if (inputString.startsWith(mappedStr, strIndex)) {
+ return backtrack(pattern, inputString, patternIndex + 1, strIndex + mappedStr.length(), patternMap, strMap);
+ } else {
+ return false;
+ }
+ }
+
+ for (int end = strIndex + 1; end <= inputString.length(); end++) {
+ String substring = inputString.substring(strIndex, end);
+ if (strMap.containsKey(substring)) {
+ continue;
+ }
+
+ patternMap.put(currentChar, substring);
+ strMap.put(substring, currentChar);
+ if (backtrack(pattern, inputString, patternIndex + 1, end, patternMap, strMap)) {
+ return true;
+ }
+
+ patternMap.remove(currentChar);
+ strMap.remove(substring);
+ }
+
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/backtracking/WordSearch.java b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
new file mode 100644
index 000000000000..174ca90ccaab
--- /dev/null
+++ b/src/main/java/com/thealgorithms/backtracking/WordSearch.java
@@ -0,0 +1,109 @@
+package com.thealgorithms.backtracking;
+
+/**
+ * Word Search Problem
+ *
+ * This class solves the word search problem where given an m x n grid of characters (board)
+ * and a target word, the task is to check if the word exists in the grid.
+ * The word can be constructed from sequentially adjacent cells (horizontally or vertically),
+ * and the same cell may not be used more than once in constructing the word.
+ *
+ * Example:
+ * - For board =
+ * [
+ * ['A','B','C','E'],
+ * ['S','F','C','S'],
+ * ['A','D','E','E']
+ * ]
+ * and word = "ABCCED", -> returns true
+ * and word = "SEE", -> returns true
+ * and word = "ABCB", -> returns false
+ *
+ * Solution:
+ * - Depth First Search (DFS) with backtracking is used to explore possible paths from any cell
+ * matching the first letter of the word. DFS ensures that we search all valid paths, while
+ * backtracking helps in reverting decisions when a path fails to lead to a solution.
+ *
+ * Time Complexity: O(m * n * 3^L)
+ * - m = number of rows in the board
+ * - n = number of columns in the board
+ * - L = length of the word
+ * - For each cell, we look at 3 possible directions (since we exclude the previously visited direction),
+ * and we do this for L letters.
+ *
+ * Space Complexity: O(L)
+ * - Stack space for the recursive DFS function, where L is the maximum depth of recursion (length of the word).
+ */
+public class WordSearch {
+ private final int[] dx = {0, 0, 1, -1};
+ private final int[] dy = {1, -1, 0, 0};
+ private boolean[][] visited;
+ private char[][] board;
+ private String word;
+
+ /**
+ * Checks if the given (x, y) coordinates are valid positions in the board.
+ *
+ * @param x The row index.
+ * @param y The column index.
+ * @return True if the coordinates are within the bounds of the board; false otherwise.
+ */
+ private boolean isValid(int x, int y) {
+ return x >= 0 && x < board.length && y >= 0 && y < board[0].length;
+ }
+
+ /**
+ * Performs Depth First Search (DFS) from the cell (x, y)
+ * to search for the next character in the word.
+ *
+ * @param x The current row index.
+ * @param y The current column index.
+ * @param nextIdx The index of the next character in the word to be matched.
+ * @return True if a valid path is found to match the remaining characters of the word; false otherwise.
+ */
+ private boolean doDFS(int x, int y, int nextIdx) {
+ visited[x][y] = true;
+ if (nextIdx == word.length()) {
+ return true;
+ }
+
+ for (int i = 0; i < 4; ++i) {
+ int xi = x + dx[i];
+ int yi = y + dy[i];
+ if (isValid(xi, yi) && board[xi][yi] == word.charAt(nextIdx) && !visited[xi][yi]) {
+ boolean exists = doDFS(xi, yi, nextIdx + 1);
+ if (exists) {
+ return true;
+ }
+ }
+ }
+
+ visited[x][y] = false; // Backtrack
+ return false;
+ }
+
+ /**
+ * Main function to check if the word exists in the board. It initiates DFS from any
+ * cell that matches the first character of the word.
+ *
+ * @param board The 2D grid of characters (the board).
+ * @param word The target word to search for in the board.
+ * @return True if the word exists in the board; false otherwise.
+ */
+ public boolean exist(char[][] board, String word) {
+ this.board = board;
+ this.word = word;
+ for (int i = 0; i < board.length; ++i) {
+ for (int j = 0; j < board[0].length; ++j) {
+ if (board[i][j] == word.charAt(0)) {
+ visited = new boolean[board.length][board[0].length];
+ boolean exists = doDFS(i, j, 1);
+ if (exists) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java b/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java
new file mode 100644
index 000000000000..e6bd35720d9f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BcdConversion.java
@@ -0,0 +1,82 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides methods to convert between BCD (Binary-Coded Decimal) and decimal numbers.
+ *
+ * BCD is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of binary digits, usually four or eight.
+ *
+ * For more information, refer to the
+ * Binary-Coded Decimal Wikipedia page.
+ *
+ * Example usage:
+ *
+ * int decimal = BcdConversion.bcdToDecimal(0x1234);
+ * System.out.println("BCD 0x1234 to decimal: " + decimal); // Output: 1234
+ *
+ * int bcd = BcdConversion.decimalToBcd(1234);
+ * System.out.println("Decimal 1234 to BCD: " + Integer.toHexString(bcd)); // Output: 0x1234
+ *
+ */
+public final class BcdConversion {
+ private BcdConversion() {
+ }
+
+ /**
+ * Converts a BCD (Binary-Coded Decimal) number to a decimal number.
+ * Steps:
+ *
1. Validate the BCD number to ensure all digits are between 0 and 9.
+ *
2. Extract the last 4 bits (one BCD digit) from the BCD number.
+ *
3. Multiply the extracted digit by the corresponding power of 10 and add it to the decimal number.
+ *
4. Shift the BCD number right by 4 bits to process the next BCD digit.
+ *
5. Repeat steps 1-4 until the BCD number is zero.
+ *
+ * @param bcd The BCD number.
+ * @return The corresponding decimal number.
+ * @throws IllegalArgumentException if the BCD number contains invalid digits.
+ */
+ public static int bcdToDecimal(int bcd) {
+ int decimal = 0;
+ int multiplier = 1;
+
+ // Validate BCD digits
+ while (bcd > 0) {
+ int digit = bcd & 0xF;
+ if (digit > 9) {
+ throw new IllegalArgumentException("Invalid BCD digit: " + digit);
+ }
+ decimal += digit * multiplier;
+ multiplier *= 10;
+ bcd >>= 4;
+ }
+ return decimal;
+ }
+
+ /**
+ * Converts a decimal number to BCD (Binary-Coded Decimal).
+ *
Steps:
+ *
1. Check if the decimal number is within the valid range for BCD (0 to 9999).
+ *
2. Extract the last decimal digit from the decimal number.
+ *
3. Shift the digit to the correct BCD position and add it to the BCD number.
+ *
4. Remove the last decimal digit from the decimal number.
+ *
5. Repeat steps 2-4 until the decimal number is zero.
+ *
+ * @param decimal The decimal number.
+ * @return The corresponding BCD number.
+ * @throws IllegalArgumentException if the decimal number is greater than 9999.
+ */
+ public static int decimalToBcd(int decimal) {
+ if (decimal < 0 || decimal > 9999) {
+ throw new IllegalArgumentException("Value out of bounds for BCD representation: " + decimal);
+ }
+
+ int bcd = 0;
+ int shift = 0;
+ while (decimal > 0) {
+ int digit = decimal % 10;
+ bcd |= (digit << (shift * 4));
+ decimal /= 10;
+ shift++;
+ }
+ return bcd;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
new file mode 100644
index 000000000000..0d6fd140c720
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BinaryPalindromeCheck.java
@@ -0,0 +1,43 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class contains a method to check if the binary representation of a number is a palindrome.
+ *
+ * A binary palindrome is a number whose binary representation is the same when read from left to right and right to left.
+ * For example, the number 9 has a binary representation of 1001, which is a palindrome.
+ * The number 10 has a binary representation of 1010, which is not a palindrome.
+ *
+ *
+ * @author Hardvan
+ */
+public final class BinaryPalindromeCheck {
+ private BinaryPalindromeCheck() {
+ }
+
+ /**
+ * Checks if the binary representation of a number is a palindrome.
+ *
+ * @param x The number to check.
+ * @return True if the binary representation is a palindrome, otherwise false.
+ */
+ public static boolean isBinaryPalindrome(int x) {
+ int reversed = reverseBits(x);
+ return x == reversed;
+ }
+
+ /**
+ * Helper function to reverse all the bits of an integer.
+ *
+ * @param x The number to reverse the bits of.
+ * @return The number with reversed bits.
+ */
+ private static int reverseBits(int x) {
+ int result = 0;
+ while (x > 0) {
+ result <<= 1;
+ result |= (x & 1);
+ x >>= 1;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java
new file mode 100644
index 000000000000..226e09e78d1f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitRotate.java
@@ -0,0 +1,83 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for performing circular bit rotations on 32-bit integers.
+ * Bit rotation is a circular shift operation where bits shifted out on one end
+ * are reinserted on the opposite end.
+ *
+ * This class provides methods for both left and right circular rotations,
+ * supporting only 32-bit integer operations with proper shift normalization
+ * and error handling.
+ *
+ * @see Bit Rotation
+ */
+public final class BitRotate {
+
+ /**
+ * Private constructor to prevent instantiation.
+ * This is a utility class with only static methods.
+ */
+ private BitRotate() {
+ throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
+ }
+
+ /**
+ * Performs a circular left rotation (left shift) on a 32-bit integer.
+ * Bits shifted out from the left side are inserted on the right side.
+ *
+ * @param value the 32-bit integer value to rotate
+ * @param shift the number of positions to rotate left (must be non-negative)
+ * @return the result of left rotating the value by the specified shift amount
+ * @throws IllegalArgumentException if shift is negative
+ *
+ * @example
+ * // Binary: 10000000 00000000 00000000 00000001
+ * rotateLeft(0x80000001, 1)
+ * // Returns: 3 (binary: 00000000 00000000 00000000 00000011)
+ */
+ public static int rotateLeft(int value, int shift) {
+ if (shift < 0) {
+ throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
+ }
+
+ // Normalize shift to the range [0, 31] using modulo 32
+ shift = shift % 32;
+
+ if (shift == 0) {
+ return value;
+ }
+
+ // Left rotation: (value << shift) | (value >>> (32 - shift))
+ return (value << shift) | (value >>> (32 - shift));
+ }
+
+ /**
+ * Performs a circular right rotation (right shift) on a 32-bit integer.
+ * Bits shifted out from the right side are inserted on the left side.
+ *
+ * @param value the 32-bit integer value to rotate
+ * @param shift the number of positions to rotate right (must be non-negative)
+ * @return the result of right rotating the value by the specified shift amount
+ * @throws IllegalArgumentException if shift is negative
+ *
+ * @example
+ * // Binary: 00000000 00000000 00000000 00000011
+ * rotateRight(3, 1)
+ * // Returns: -2147483647 (binary: 10000000 00000000 00000000 00000001)
+ */
+ public static int rotateRight(int value, int shift) {
+ if (shift < 0) {
+ throw new IllegalArgumentException("Shift amount cannot be negative: " + shift);
+ }
+
+ // Normalize shift to the range [0, 31] using modulo 32
+ shift = shift % 32;
+
+ if (shift == 0) {
+ return value;
+ }
+
+ // Right rotation: (value >>> shift) | (value << (32 - shift))
+ return (value >>> shift) | (value << (32 - shift));
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java
new file mode 100644
index 000000000000..634c9e7b3b44
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitSwap.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for performing bit-swapping operations on integers.
+ * This class cannot be instantiated.
+ */
+public final class BitSwap {
+ private BitSwap() {
+ }
+
+ /**
+ * Swaps two bits at specified positions in an integer.
+ *
+ * @param data The input integer whose bits need to be swapped
+ * @param posA The position of the first bit (0-based, from least significant)
+ * @param posB The position of the second bit (0-based, from least significant)
+ * @return The modified value with swapped bits
+ * @throws IllegalArgumentException if either position is negative or ≥ 32
+ */
+
+ public static int bitSwap(int data, final int posA, final int posB) {
+ if (posA < 0 || posA >= Integer.SIZE || posB < 0 || posB >= Integer.SIZE) {
+ throw new IllegalArgumentException("Bit positions must be between 0 and 31");
+ }
+
+ boolean bitA = ((data >> posA) & 1) != 0;
+ boolean bitB = ((data >> posB) & 1) != 0;
+ if (bitA != bitB) {
+ data ^= (1 << posA) ^ (1 << posB);
+ }
+ return data;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java b/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java
new file mode 100644
index 000000000000..516563459256
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BitwiseGCD.java
@@ -0,0 +1,147 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.math.BigInteger;
+
+/**
+ * Bitwise GCD implementation with full-range support utilities.
+ *
+ * This class provides a fast binary (Stein's) GCD implementation for {@code long}
+ * inputs and a BigInteger-backed API for full 2's-complement range support (including
+ * {@code Long.MIN_VALUE}). The {@code long} implementation is efficient and avoids
+ * division/modulo operations. For edge-cases that overflow signed-64-bit ranges
+ * (e.g., gcd(Long.MIN_VALUE, 0) = 2^63), use the BigInteger API {@code gcdBig}.
+ *
+ *
Behaviour:
+ *
+ * - {@code gcd(long,long)} : returns non-negative {@code long} gcd for inputs whose
+ * absolute values fit in signed {@code long} (i.e., not causing an unsigned 2^63 result).
+ * If the true gcd does not fit in a signed {@code long} (for example gcd(Long.MIN_VALUE,0) = 2^63)
+ * this method will delegate to BigInteger and throw {@link ArithmeticException} if the
+ * BigInteger result does not fit into a signed {@code long}.
+ * - {@code gcdBig(BigInteger, BigInteger)} : returns the exact gcd as a {@link BigInteger}
+ * and works for the full signed-64-bit range and beyond.
+ *
+ */
+public final class BitwiseGCD {
+
+ private BitwiseGCD() {
+ }
+
+ /**
+ * Computes GCD of two long values using Stein's algorithm (binary GCD).
+ * Handles negative inputs. If either input is {@code Long.MIN_VALUE} the
+ * method delegates to the BigInteger implementation and will throw {@link ArithmeticException}
+ * if the result cannot be represented as a signed {@code long}.
+ *
+ * @param a first value (may be negative)
+ * @param b second value (may be negative)
+ * @return non-negative gcd as a {@code long}
+ * @throws ArithmeticException when the exact gcd does not fit into a signed {@code long}
+ */
+ public static long gcd(long a, long b) {
+ // Trivial cases
+ if (a == 0L) {
+ return absOrThrowIfOverflow(b);
+ }
+ if (b == 0L) {
+ return absOrThrowIfOverflow(a);
+ }
+
+ // If either is Long.MIN_VALUE, absolute value doesn't fit into signed long.
+ if (a == Long.MIN_VALUE || b == Long.MIN_VALUE) {
+ // Delegate to BigInteger and try to return a long if it fits
+ BigInteger g = gcdBig(BigInteger.valueOf(a), BigInteger.valueOf(b));
+ return g.longValueExact();
+ }
+
+ // Work with non-negative long values now (safe because we excluded Long.MIN_VALUE)
+ a = (a < 0) ? -a : a;
+ b = (b < 0) ? -b : b;
+
+ // Count common factors of 2
+ int commonTwos = Long.numberOfTrailingZeros(a | b);
+
+ // Remove all factors of 2 from a
+ a >>= Long.numberOfTrailingZeros(a);
+
+ while (b != 0L) {
+ // Remove all factors of 2 from b
+ b >>= Long.numberOfTrailingZeros(b);
+
+ // Now both a and b are odd. Ensure a <= b
+ if (a > b) {
+ long tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ // b >= a; subtract a from b (result is even)
+ b = b - a;
+ }
+
+ // Restore common powers of two
+ return a << commonTwos;
+ }
+
+ /**
+ * Helper to return absolute value of x unless x == Long.MIN_VALUE, in which
+ * case we delegate to BigInteger and throw to indicate overflow.
+ */
+ private static long absOrThrowIfOverflow(long x) {
+ if (x == Long.MIN_VALUE) {
+ // |Long.MIN_VALUE| = 2^63 which does not fit into signed long
+ throw new ArithmeticException("Absolute value of Long.MIN_VALUE does not fit into signed long. Use gcdBig() for full-range support.");
+ }
+ return (x < 0) ? -x : x;
+ }
+
+ /**
+ * Computes GCD for an array of {@code long} values. Returns 0 for empty/null arrays.
+ * If any intermediate gcd cannot be represented in signed long (rare), an ArithmeticException
+ * will be thrown.
+ */
+ public static long gcd(long... values) {
+
+ if (values == null || values.length == 0) {
+ return 0L;
+ }
+ long result = values[0];
+ for (int i = 1; i < values.length; i++) {
+ result = gcd(result, values[i]);
+ if (result == 1L) {
+ return 1L; // early exit
+ }
+ }
+ return result;
+ }
+
+ /**
+ * BigInteger-backed gcd that works for the full integer range (and beyond).
+ * This is the recommended method when inputs may be Long.MIN_VALUE or when you
+ * need an exact result even if it is greater than Long.MAX_VALUE.
+ * @param a first value (may be negative)
+ * @param b second value (may be negative)
+ * @return non-negative gcd as a {@link BigInteger}
+ */
+ public static BigInteger gcdBig(BigInteger a, BigInteger b) {
+
+ if (a == null || b == null) {
+ throw new NullPointerException("Arguments must not be null");
+ }
+ return a.abs().gcd(b.abs());
+ }
+
+ /**
+ * Convenience overload that accepts signed-64 inputs and returns BigInteger gcd.
+ */
+ public static BigInteger gcdBig(long a, long b) {
+ return gcdBig(BigInteger.valueOf(a), BigInteger.valueOf(b));
+ }
+
+ /**
+ * int overload for convenience.
+ */
+ public static int gcd(int a, int b) {
+ return (int) gcd((long) a, (long) b);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
new file mode 100644
index 000000000000..869466320831
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/BooleanAlgebraGates.java
@@ -0,0 +1,111 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.List;
+
+/**
+ * Implements various Boolean algebra gates (AND, OR, NOT, XOR, NAND, NOR)
+ */
+public final class BooleanAlgebraGates {
+
+ private BooleanAlgebraGates() {
+ // Prevent instantiation
+ }
+
+ /**
+ * Represents a Boolean gate that takes multiple inputs and returns a result.
+ */
+ interface BooleanGate {
+ /**
+ * Evaluates the gate with the given inputs.
+ *
+ * @param inputs The input values for the gate.
+ * @return The result of the evaluation.
+ */
+ boolean evaluate(List inputs);
+ }
+
+ /**
+ * AND Gate implementation.
+ * Returns true if all inputs are true; otherwise, false.
+ */
+ static class ANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (!input) {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ /**
+ * OR Gate implementation.
+ * Returns true if at least one input is true; otherwise, false.
+ */
+ static class ORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ for (boolean input : inputs) {
+ if (input) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * NOT Gate implementation (Unary operation).
+ * Negates a single input value.
+ */
+ static class NOTGate {
+ /**
+ * Evaluates the negation of the input.
+ *
+ * @param input The input value to be negated.
+ * @return The negated value.
+ */
+ public boolean evaluate(boolean input) {
+ return !input;
+ }
+ }
+
+ /**
+ * XOR Gate implementation.
+ * Returns true if an odd number of inputs are true; otherwise, false.
+ */
+ static class XORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ boolean result = false;
+ for (boolean input : inputs) {
+ result ^= input;
+ }
+ return result;
+ }
+ }
+
+ /**
+ * NAND Gate implementation.
+ * Returns true if at least one input is false; otherwise, false.
+ */
+ static class NANDGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ANDGate().evaluate(inputs); // Equivalent to negation of AND
+ }
+ }
+
+ /**
+ * NOR Gate implementation.
+ * Returns true if all inputs are false; otherwise, false.
+ */
+ static class NORGate implements BooleanGate {
+ @Override
+ public boolean evaluate(List inputs) {
+ return !new ORGate().evaluate(inputs); // Equivalent to negation of OR
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
new file mode 100644
index 000000000000..3e9a4a21183f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ClearLeftmostSetBit.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * ClearLeftmostSetBit class contains a method to clear the leftmost set bit of a number.
+ * The leftmost set bit is the leftmost bit that is set to 1 in the binary representation of a number.
+ *
+ * Example:
+ * 26 (11010) -> 10 (01010)
+ * 1 (1) -> 0 (0)
+ * 7 (111) -> 3 (011)
+ * 6 (0110) -> 2 (0010)
+ *
+ * @author Hardvan
+ */
+public final class ClearLeftmostSetBit {
+ private ClearLeftmostSetBit() {
+ }
+
+ /**
+ * Clears the leftmost set bit (1) of a given number.
+ * Step 1: Find the position of the leftmost set bit
+ * Step 2: Create a mask with all bits set except for the leftmost set bit
+ * Step 3: Clear the leftmost set bit using AND with the mask
+ *
+ * @param num The input number.
+ * @return The number after clearing the leftmost set bit.
+ */
+ public static int clearLeftmostSetBit(int num) {
+ int pos = 0;
+ int temp = num;
+ while (temp > 0) {
+ temp >>= 1;
+ pos++;
+ }
+
+ int mask = ~(1 << (pos - 1));
+ return num & mask;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java b/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java
new file mode 100644
index 000000000000..8d2c757e5e0a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountBitsFlip.java
@@ -0,0 +1,63 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Implementation to count number of bits to be flipped to convert A to B
+ *
+ * Problem: Given two numbers A and B, count the number of bits needed to be
+ * flipped to convert A to B.
+ *
+ * Example:
+ * A = 10 (01010 in binary)
+ * B = 20 (10100 in binary)
+ * XOR = 30 (11110 in binary) - positions where bits differ
+ * Answer: 4 bits need to be flipped
+ *
+ * Time Complexity: O(log n) - where n is the number of set bits
+ * Space Complexity: O(1)
+ *
+ *@author [Yash Rajput](https://github.com/the-yash-rajput)
+ */
+public final class CountBitsFlip {
+
+ private CountBitsFlip() {
+ throw new AssertionError("No instances.");
+ }
+
+ /**
+ * Counts the number of bits that need to be flipped to convert a to b
+ *
+ * Algorithm:
+ * 1. XOR a and b to get positions where bits differ
+ * 2. Count the number of set bits in the XOR result
+ * 3. Use Brian Kernighan's algorithm: n & (n-1) removes rightmost set bit
+ *
+ * @param a the source number
+ * @param b the target number
+ * @return the number of bits to flip to convert A to B
+ */
+ public static long countBitsFlip(long a, long b) {
+ int count = 0;
+
+ // XOR gives us positions where bits differ
+ long xorResult = a ^ b;
+
+ // Count set bits using Brian Kernighan's algorithm
+ while (xorResult != 0) {
+ xorResult = xorResult & (xorResult - 1); // Remove rightmost set bit
+ count++;
+ }
+
+ return count;
+ }
+
+ /**
+ * Alternative implementation using Long.bitCount().
+ *
+ * @param a the source number
+ * @param b the target number
+ * @return the number of bits to flip to convert a to b
+ */
+ public static long countBitsFlipAlternative(long a, long b) {
+ return Long.bitCount(a ^ b);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
new file mode 100644
index 000000000000..318334f0b951
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountLeadingZeros.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * CountLeadingZeros class contains a method to count the number of leading zeros in the binary representation of a number.
+ * The number of leading zeros is the number of zeros before the leftmost 1 bit.
+ * For example, the number 5 has 29 leading zeros in its 32-bit binary representation.
+ * The number 0 has 32 leading zeros.
+ * The number 1 has 31 leading zeros.
+ * The number -1 has no leading zeros.
+ *
+ * @author Hardvan
+ */
+public final class CountLeadingZeros {
+ private CountLeadingZeros() {
+ }
+
+ /**
+ * Counts the number of leading zeros in the binary representation of a number.
+ * Method: Keep shifting the mask to the right until the leftmost bit is 1.
+ * The number of shifts is the number of leading zeros.
+ *
+ * @param num The input number.
+ * @return The number of leading zeros.
+ */
+ public static int countLeadingZeros(int num) {
+ if (num == 0) {
+ return 32;
+ }
+
+ int count = 0;
+ int mask = 1 << 31;
+ while ((mask & num) == 0) {
+ count++;
+ mask >>>= 1;
+ }
+
+ return count;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
new file mode 100644
index 000000000000..7df522ca8f69
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/CountSetBits.java
@@ -0,0 +1,79 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class to count total set bits from 1 to N
+ * A set bit is a bit in binary representation that is 1
+ *
+ * @author navadeep
+ */
+public final class CountSetBits {
+
+ private CountSetBits() {
+ // Utility class, prevent instantiation
+ }
+
+ /**
+ * Counts total number of set bits in all numbers from 1 to n
+ * Time Complexity: O(log n)
+ *
+ * @param n the upper limit (inclusive)
+ * @return total count of set bits from 1 to n
+ * @throws IllegalArgumentException if n is negative
+ */
+ public static int countSetBits(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative");
+ }
+
+ if (n == 0) {
+ return 0;
+ }
+
+ // Find the largest power of 2 <= n
+ int x = largestPowerOf2InNumber(n);
+
+ // Total bits at position x: x * 2^(x-1)
+ int bitsAtPositionX = x * (1 << (x - 1));
+
+ // Remaining numbers after 2^x
+ int remainingNumbers = n - (1 << x) + 1;
+
+ // Recursively count for the rest
+ int rest = countSetBits(n - (1 << x));
+
+ return bitsAtPositionX + remainingNumbers + rest;
+ }
+
+ /**
+ * Finds the position of the most significant bit in n
+ *
+ * @param n the number
+ * @return position of MSB (0-indexed from right)
+ */
+ private static int largestPowerOf2InNumber(int n) {
+ int position = 0;
+ while ((1 << position) <= n) {
+ position++;
+ }
+ return position - 1;
+ }
+
+ /**
+ * Alternative naive approach - counts set bits by iterating through all numbers
+ * Time Complexity: O(n log n)
+ *
+ * @param n the upper limit (inclusive)
+ * @return total count of set bits from 1 to n
+ */
+ public static int countSetBitsNaive(int n) {
+ if (n < 0) {
+ throw new IllegalArgumentException("Input must be non-negative");
+ }
+
+ int count = 0;
+ for (int i = 1; i <= n; i++) {
+ count += Integer.bitCount(i);
+ }
+ return count;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
new file mode 100644
index 000000000000..7a35fc3feebf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/FindNthBit.java
@@ -0,0 +1,46 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to find the Nth bit of a given number.
+ *
+ * This class provides a method to extract the value of the Nth bit (either 0 or 1)
+ * from the binary representation of a given integer.
+ *
+ *
Example:
+ *
{@code
+ * int result = FindNthBit.findNthBit(5, 2); // returns 0 as the 2nd bit of 5 (binary 101) is 0.
+ * }
+ *
+ * Author: Tuhinm2002
+ */
+public final class FindNthBit {
+
+ /**
+ * Private constructor to prevent instantiation.
+ *
+ *
This is a utility class, and it should not be instantiated.
+ * Attempting to instantiate this class will throw an UnsupportedOperationException.
+ */
+ private FindNthBit() {
+ throw new UnsupportedOperationException("Utility class");
+ }
+
+ /**
+ * Finds the value of the Nth bit of the given number.
+ *
+ *
This method uses bitwise operations to extract the Nth bit from the
+ * binary representation of the given integer.
+ *
+ * @param num the integer number whose Nth bit is to be found
+ * @param n the bit position (1-based) to retrieve
+ * @return the value of the Nth bit (0 or 1)
+ * @throws IllegalArgumentException if the bit position is less than 1
+ */
+ public static int findNthBit(int num, int n) {
+ if (n < 1) {
+ throw new IllegalArgumentException("Bit position must be greater than or equal to 1.");
+ }
+ // Shifting the number to the right by (n - 1) positions and checking the last bit
+ return (num & (1 << (n - 1))) >> (n - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java b/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java
new file mode 100644
index 000000000000..9a761c572e2c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/FirstDifferentBit.java
@@ -0,0 +1,33 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the first differing bit
+ * between two integers.
+ *
+ * Example:
+ * x = 10 (1010 in binary)
+ * y = 12 (1100 in binary)
+ * The first differing bit is at index 1 (0-based)
+ * So, the output will be 1
+ *
+ * @author Hardvan
+ */
+public final class FirstDifferentBit {
+ private FirstDifferentBit() {
+ }
+
+ /**
+ * Identifies the index of the first differing bit between two integers.
+ * Steps:
+ * 1. XOR the two integers to get the differing bits
+ * 2. Find the index of the first set bit in XOR result
+ *
+ * @param x the first integer
+ * @param y the second integer
+ * @return the index of the first differing bit (0-based)
+ */
+ public static int firstDifferentBit(int x, int y) {
+ int diff = x ^ y;
+ return Integer.numberOfTrailingZeros(diff);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java b/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java
new file mode 100644
index 000000000000..f1b812495c1b
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/GenerateSubsets.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This class provides a method to generate all subsets (power set)
+ * of a given set using bit manipulation.
+ *
+ * @author Hardvan
+ */
+public final class GenerateSubsets {
+ private GenerateSubsets() {
+ }
+
+ /**
+ * Generates all subsets of a given set using bit manipulation.
+ * Steps:
+ * 1. Iterate over all numbers from 0 to 2^n - 1.
+ * 2. For each number, iterate over all bits from 0 to n - 1.
+ * 3. If the i-th bit of the number is set, add the i-th element of the set to the current subset.
+ * 4. Add the current subset to the list of subsets.
+ * 5. Return the list of subsets.
+ *
+ * @param set the input set of integers
+ * @return a list of all subsets represented as lists of integers
+ */
+ public static List> generateSubsets(int[] set) {
+ int n = set.length;
+ List> subsets = new ArrayList<>();
+
+ for (int mask = 0; mask < (1 << n); mask++) {
+ List subset = new ArrayList<>();
+ for (int i = 0; i < n; i++) {
+ if ((mask & (1 << i)) != 0) {
+ subset.add(set[i]);
+ }
+ }
+ subsets.add(subset);
+ }
+
+ return subsets;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
new file mode 100644
index 000000000000..83cd30c7d50a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/GrayCodeConversion.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Gray code is a binary numeral system where two successive values differ in only one bit.
+ * This is a simple conversion between binary and Gray code.
+ * Example:
+ * 7 -> 0111 -> 0100 -> 4
+ * 4 -> 0100 -> 0111 -> 7
+ * 0 -> 0000 -> 0000 -> 0
+ * 1 -> 0001 -> 0000 -> 0
+ * 2 -> 0010 -> 0011 -> 3
+ * 3 -> 0011 -> 0010 -> 2
+ *
+ * @author Hardvan
+ */
+public final class GrayCodeConversion {
+ private GrayCodeConversion() {
+ }
+
+ /**
+ * Converts a binary number to Gray code.
+ *
+ * @param num The binary number.
+ * @return The corresponding Gray code.
+ */
+ public static int binaryToGray(int num) {
+ return num ^ (num >> 1);
+ }
+
+ /**
+ * Converts a Gray code number back to binary.
+ *
+ * @param gray The Gray code number.
+ * @return The corresponding binary number.
+ */
+ public static int grayToBinary(int gray) {
+ int binary = gray;
+ while (gray > 0) {
+ gray >>= 1;
+ binary ^= gray;
+ }
+ return binary;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
new file mode 100644
index 000000000000..4c24909ef234
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HammingDistance.java
@@ -0,0 +1,29 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * The Hamming distance between two integers is the number of positions at which the corresponding bits are different.
+ * Given two integers x and y, calculate the Hamming distance.
+ * Example:
+ * Input: x = 1, y = 4
+ * Output: 2
+ * Explanation: 1 (0001) and 4 (0100) have 2 differing bits.
+ *
+ * @author Hardvan
+ */
+public final class HammingDistance {
+ private HammingDistance() {
+ }
+
+ /**
+ * Calculates the Hamming distance between two integers.
+ * The Hamming distance is the number of differing bits between the two integers.
+ *
+ * @param x The first integer.
+ * @param y The second integer.
+ * @return The Hamming distance (number of differing bits).
+ */
+ public static int hammingDistance(int x, int y) {
+ int xor = x ^ y;
+ return Integer.bitCount(xor);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
new file mode 100644
index 000000000000..0fb058b2b8a3
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HigherLowerPowerOfTwo.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * HigherLowerPowerOfTwo class has two methods to find the next higher and lower power of two.
+ *
+ * nextHigherPowerOfTwo method finds the next higher power of two.
+ * nextLowerPowerOfTwo method finds the next lower power of two.
+ * Both methods take an integer as input and return the next higher or lower power of two.
+ * If the input is less than 1, the next higher power of two is 1.
+ * If the input is less than or equal to 1, the next lower power of two is 0.
+ * nextHigherPowerOfTwo method uses bitwise operations to find the next higher power of two.
+ * nextLowerPowerOfTwo method uses Integer.highestOneBit method to find the next lower power of two.
+ * The time complexity of both methods is O(1).
+ * The space complexity of both methods is O(1).
+ *
+ *
+ * @author Hardvan
+ */
+public final class HigherLowerPowerOfTwo {
+ private HigherLowerPowerOfTwo() {
+ }
+
+ /**
+ * Finds the next higher power of two.
+ *
+ * @param x The given number.
+ * @return The next higher power of two.
+ */
+ public static int nextHigherPowerOfTwo(int x) {
+ if (x < 1) {
+ return 1;
+ }
+ x--;
+ x |= x >> 1;
+ x |= x >> 2;
+ x |= x >> 4;
+ x |= x >> 8;
+ x |= x >> 16;
+ return x + 1;
+ }
+
+ /**
+ * Finds the next lower power of two.
+ *
+ * @param x The given number.
+ * @return The next lower power of two.
+ */
+ public static int nextLowerPowerOfTwo(int x) {
+ if (x < 1) {
+ return 0;
+ }
+ return Integer.highestOneBit(x);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java
new file mode 100644
index 000000000000..2398b8214371
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/HighestSetBit.java
@@ -0,0 +1,54 @@
+package com.thealgorithms.bitmanipulation;
+
+import java.util.Optional;
+
+/**
+ * Find Highest Set Bit
+ *
+ * This class provides a utility method to calculate the position of the highest
+ * (most significant) bit that is set to 1 in a given non-negative integer.
+ * It is often used in bit manipulation tasks to find the left-most set bit in binary
+ * representation of a number.
+ *
+ * Example:
+ * - For input 18 (binary 10010), the highest set bit is at position 4 (zero-based index).
+ *
+ * @author Bama Charan Chhandogi
+ * @version 1.0
+ * @since 2021-06-23
+ */
+public final class HighestSetBit {
+
+ private HighestSetBit() {
+ }
+
+ /**
+ * Finds the highest (most significant) set bit in the given integer.
+ * The method returns the position (index) of the highest set bit as an {@link Optional}.
+ *
+ * - If the number is 0, no bits are set, and the method returns {@link Optional#empty()}.
+ * - If the number is negative, the method throws {@link IllegalArgumentException}.
+ *
+ * @param num The input integer for which the highest set bit is to be found. It must be non-negative.
+ * @return An {@link Optional} containing the index of the highest set bit (zero-based).
+ * Returns {@link Optional#empty()} if the number is 0.
+ * @throws IllegalArgumentException if the input number is negative.
+ */
+ public static Optional findHighestSetBit(int num) {
+ if (num < 0) {
+ throw new IllegalArgumentException("Input cannot be negative");
+ }
+
+ if (num == 0) {
+ return Optional.empty();
+ }
+
+ int position = 0;
+ while (num > 0) {
+ num >>= 1;
+ position++;
+ }
+
+ return Optional.of(position - 1); // Subtract 1 to convert to zero-based index
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java
new file mode 100644
index 000000000000..1b8962344ea7
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IndexOfRightMostSetBit.java
@@ -0,0 +1,44 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for bit manipulation operations.
+ * This class provides methods to work with bitwise operations.
+ * Specifically, it includes a method to find the index of the rightmost set bit
+ * in an integer.
+ * This class is not meant to be instantiated.
+ *
+ * Author: Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class IndexOfRightMostSetBit {
+
+ private IndexOfRightMostSetBit() {
+ }
+
+ /**
+ * Finds the index of the rightmost set bit in the given integer.
+ * The index is zero-based, meaning the rightmost bit has an index of 0.
+ *
+ * @param n the integer to check for the rightmost set bit
+ * @return the index of the rightmost set bit; -1 if there are no set bits
+ * (i.e., the input integer is 0)
+ */
+ public static int indexOfRightMostSetBit(int n) {
+ if (n == 0) {
+ return -1; // No set bits
+ }
+
+ // Handle negative numbers by finding the two's complement
+ if (n < 0) {
+ n = -n;
+ n = n & (~n + 1); // Isolate the rightmost set bit
+ }
+
+ int index = 0;
+ while ((n & 1) == 0) {
+ n = n >> 1;
+ index++;
+ }
+
+ return index;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java b/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java
new file mode 100644
index 000000000000..09d5383322ff
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IsEven.java
@@ -0,0 +1,14 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Checks whether a number is even
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+
+public final class IsEven {
+ private IsEven() {
+ }
+ public static boolean isEven(int number) {
+ return (number & 1) == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java
new file mode 100644
index 000000000000..4cdf3c6faa3e
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/IsPowerTwo.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class for checking if a number is a power of two.
+ * A power of two is a number that can be expressed as 2^n where n is a non-negative integer.
+ * This class provides a method to determine if a given integer is a power of two using bit manipulation.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class IsPowerTwo {
+ private IsPowerTwo() {
+ }
+
+ /**
+ * Checks if the given integer is a power of two.
+ *
+ * A number is considered a power of two if it is greater than zero and
+ * has exactly one '1' bit in its binary representation. This method
+ * uses the property that for any power of two (n), the expression
+ * (n & (n - 1)) will be zero.
+ *
+ * @param number the integer to check
+ * @return true if the number is a power of two, false otherwise
+ */
+ public static boolean isPowerTwo(int number) {
+ if (number <= 0) {
+ return false;
+ }
+ int ans = number & (number - 1);
+ return ans == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java b/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java
new file mode 100644
index 000000000000..127b6fa2c0b1
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/LowestSetBit.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Lowest Set Bit
+ * @author Prayas Kumar (https://github.com/prayas7102)
+ */
+
+public final class LowestSetBit {
+ // Private constructor to hide the default public one
+ private LowestSetBit() {
+ }
+ /**
+ * Isolates the lowest set bit of the given number. For example, if n = 18
+ * (binary: 10010), the result will be 2 (binary: 00010).
+ *
+ * @param n the number whose lowest set bit will be isolated
+ * @return the isolated lowest set bit of n
+ */
+ public static int isolateLowestSetBit(int n) {
+ // Isolate the lowest set bit using n & -n
+ return n & -n;
+ }
+ /**
+ * Clears the lowest set bit of the given number.
+ * For example, if n = 18 (binary: 10010), the result will be 16 (binary: 10000).
+ *
+ * @param n the number whose lowest set bit will be cleared
+ * @return the number after clearing its lowest set bit
+ */
+ public static int clearLowestSetBit(int n) {
+ // Clear the lowest set bit using n & (n - 1)
+ return n & (n - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java b/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java
new file mode 100644
index 000000000000..537a046f77e4
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ModuloPowerOfTwo.java
@@ -0,0 +1,28 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to compute the remainder
+ * of a number when divided by a power of two (2^n)
+ * without using division or modulo operations.
+ *
+ * @author Hardvan
+ */
+public final class ModuloPowerOfTwo {
+ private ModuloPowerOfTwo() {
+ }
+
+ /**
+ * Computes the remainder of a given integer when divided by 2^n.
+ *
+ * @param x the input number
+ * @param n the exponent (power of two)
+ * @return the remainder of x divided by 2^n
+ */
+ public static int moduloPowerOfTwo(int x, int n) {
+ if (n <= 0) {
+ throw new IllegalArgumentException("The exponent must be positive");
+ }
+
+ return x & ((1 << n) - 1);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java b/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java
new file mode 100644
index 000000000000..6a764d806279
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NextHigherSameBitCount.java
@@ -0,0 +1,30 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the next higher number
+ * with the same number of set bits as the given number.
+ *
+ * @author Hardvan
+ */
+public final class NextHigherSameBitCount {
+ private NextHigherSameBitCount() {
+ }
+
+ /**
+ * Finds the next higher integer with the same number of set bits.
+ * Steps:
+ * 1. Find {@code c}, the rightmost set bit of {@code n}.
+ * 2. Find {@code r}, the rightmost set bit of {@code n + c}.
+ * 3. Swap the bits of {@code r} and {@code n} to the right of {@code c}.
+ * 4. Shift the bits of {@code r} and {@code n} to the right of {@code c} to the rightmost.
+ * 5. Combine the results of steps 3 and 4.
+ *
+ * @param n the input number
+ * @return the next higher integer with the same set bit count
+ */
+ public static int nextHigherSameBitCount(int n) {
+ int c = n & -n;
+ int r = n + c;
+ return (((r ^ n) >> 2) / c) | r;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java b/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java
new file mode 100644
index 000000000000..17e1a73ec062
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NonRepeatingNumberFinder.java
@@ -0,0 +1,35 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to find the non-repeating number in an array where every other number repeats.
+ * This class contains a method to identify the single unique number using bit manipulation.
+ *
+ * The solution leverages the properties of the XOR operation, which states that:
+ * - x ^ x = 0 for any integer x (a number XORed with itself is zero)
+ * - x ^ 0 = x for any integer x (a number XORed with zero is the number itself)
+ *
+ * Using these properties, we can find the non-repeating number in linear time with constant space.
+ *
+ * Example:
+ * Given the input array [2, 3, 5, 2, 3], the output will be 5 since it does not repeat.
+ *
+ * @author Bama Charan Chhandogi (https://github.com/BamaCharanChhandogi)
+ */
+public final class NonRepeatingNumberFinder {
+ private NonRepeatingNumberFinder() {
+ }
+
+ /**
+ * Finds the non-repeating number in the given array.
+ *
+ * @param arr an array of integers where every number except one appears twice
+ * @return the integer that appears only once in the array or 0 if the array is empty
+ */
+ public static int findNonRepeatingNumber(int[] arr) {
+ int result = 0;
+ for (int num : arr) {
+ result ^= num;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
new file mode 100644
index 000000000000..bd4868d4dbd5
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NumberAppearingOddTimes.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to find the element that appears an
+ * odd number of times in an array. All other elements in the array
+ * must appear an even number of times for the logic to work.
+ *
+ * The solution uses the XOR operation, which has the following properties:
+ * - a ^ a = 0 (XOR-ing the same numbers cancels them out)
+ * - a ^ 0 = a
+ * - XOR is commutative and associative.
+ *
+ * Time Complexity: O(n), where n is the size of the array.
+ * Space Complexity: O(1), as no extra space is used.
+ *
+ * Usage Example:
+ * int result = NumberAppearingOddTimes.findOddOccurrence(new int[]{1, 2, 1, 2, 3});
+ * // result will be 3
+ *
+ * @author Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+
+public final class NumberAppearingOddTimes {
+ private NumberAppearingOddTimes() {
+ }
+
+ /**
+ * Finds the element in the array that appears an odd number of times.
+ *
+ * @param arr the input array containing integers, where all elements
+ * except one appear an even number of times.
+ * @return the integer that appears an odd number of times.
+ */
+ public static int findOddOccurrence(int[] arr) {
+ int result = 0;
+ for (int num : arr) {
+ result ^= num;
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java b/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java
new file mode 100644
index 000000000000..a2da37aa81ee
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/NumbersDifferentSigns.java
@@ -0,0 +1,30 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to determine whether two integers have
+ * different signs. It utilizes the XOR operation on the two numbers:
+ *
+ * - If two numbers have different signs, their most significant bits
+ * (sign bits) will differ, resulting in a negative XOR result.
+ * - If two numbers have the same sign, the XOR result will be non-negative.
+ *
+ * Time Complexity: O(1) - Constant time operation.
+ * Space Complexity: O(1) - No extra space used.
+ *
+ * @author Bama Charan Chhandogi
+ */
+public final class NumbersDifferentSigns {
+ private NumbersDifferentSigns() {
+ }
+
+ /**
+ * Determines if two integers have different signs using bitwise XOR.
+ *
+ * @param num1 the first integer
+ * @param num2 the second integer
+ * @return true if the two numbers have different signs, false otherwise
+ */
+ public static boolean differentSigns(int num1, int num2) {
+ return (num1 ^ num2) < 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java b/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java
new file mode 100644
index 000000000000..afec0188e299
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/OneBitDifference.java
@@ -0,0 +1,32 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to detect if two integers
+ * differ by exactly one bit flip.
+ *
+ * Example:
+ * 1 (0001) and 2 (0010) differ by exactly one bit flip.
+ * 7 (0111) and 3 (0011) differ by exactly one bit flip.
+ *
+ * @author Hardvan
+ */
+public final class OneBitDifference {
+ private OneBitDifference() {
+ }
+
+ /**
+ * Checks if two integers differ by exactly one bit.
+ *
+ * @param x the first integer
+ * @param y the second integer
+ * @return true if x and y differ by exactly one bit, false otherwise
+ */
+ public static boolean differByOneBit(int x, int y) {
+ if (x == y) {
+ return false;
+ }
+
+ int xor = x ^ y;
+ return (xor & (xor - 1)) == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
new file mode 100644
index 000000000000..aae3a996e49d
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/OnesComplement.java
@@ -0,0 +1,37 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * @author - https://github.com/Monk-AbhinayVerma
+ * @Wikipedia - https://en.wikipedia.org/wiki/Ones%27_complement
+ * The class OnesComplement computes the complement of binary number
+ * and returns
+ * the complemented binary string.
+ * @return the complimented binary string
+ */
+public final class OnesComplement {
+ private OnesComplement() {
+ }
+
+ /**
+ * Returns the 1's complement of a binary string.
+ *
+ * @param binary A string representing a binary number (e.g., "1010").
+ * @return A string representing the 1's complement.
+ * @throws IllegalArgumentException if the input is null or contains characters other than '0' or '1'.
+ */
+ public static String onesComplement(String binary) {
+ if (binary == null || binary.isEmpty()) {
+ throw new IllegalArgumentException("Input must be a non-empty binary string.");
+ }
+
+ StringBuilder complement = new StringBuilder(binary.length());
+ for (char bit : binary.toCharArray()) {
+ switch (bit) {
+ case '0' -> complement.append('1');
+ case '1' -> complement.append('0');
+ default -> throw new IllegalArgumentException("Input must contain only '0' and '1'. Found: " + bit);
+ }
+ }
+ return complement.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
new file mode 100644
index 000000000000..5acab4d4a362
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ParityCheck.java
@@ -0,0 +1,34 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * The ParityCheck class provides a method to check the parity of a given number.
+ *
+ * Parity is a mathematical term that describes the property of an integer's binary representation.
+ * The parity of a binary number is the number of 1s in its binary representation.
+ * If the number of 1s is even, the parity is even; otherwise, it is odd.
+ *
+ * For example, the binary representation of 5 is 101, which has two 1s, so the parity of 5 is even.
+ * The binary representation of 6 is 110, which has two 1s, so the parity of 6 is even.
+ * The binary representation of 7 is 111, which has three 1s, so the parity of 7 is odd.
+ *
+ * @author Hardvan
+ */
+public final class ParityCheck {
+ private ParityCheck() {
+ }
+
+ /**
+ * This method checks the parity of the given number.
+ *
+ * @param n the number to check the parity of
+ * @return true if the number has even parity, false otherwise
+ */
+ public static boolean checkParity(int n) {
+ int count = 0;
+ while (n > 0) {
+ count += n & 1;
+ n >>= 1;
+ }
+ return count % 2 == 0;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java b/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java
new file mode 100644
index 000000000000..12c269d9be48
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/ReverseBits.java
@@ -0,0 +1,41 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to reverse the bits of a 32-bit integer.
+ * Reversing the bits means that the least significant bit (LSB) becomes
+ * the most significant bit (MSB) and vice versa.
+ *
+ * Example:
+ * Input (binary): 00000010100101000001111010011100 (43261596)
+ * Output (binary): 00111001011110000010100101000000 (964176192)
+ *
+ * Time Complexity: O(32) - A fixed number of 32 iterations
+ * Space Complexity: O(1) - No extra space used
+ *
+ * Note:
+ * - If the input is negative, Java handles it using two’s complement representation.
+ * - This function works on 32-bit integers by default.
+ *
+ * @author Bama Charan Chhandogi
+ */
+public final class ReverseBits {
+ private ReverseBits() {
+ }
+
+ /**
+ * Reverses the bits of a 32-bit integer.
+ *
+ * @param n the integer whose bits are to be reversed
+ * @return the integer obtained by reversing the bits of the input
+ */
+ public static int reverseBits(int n) {
+ int result = 0;
+ int bitCount = 32;
+ for (int i = 0; i < bitCount; i++) {
+ result <<= 1; // Left shift the result to make space for the next bit
+ result |= (n & 1); // OR operation to set the least significant bit of result with the current bit of n
+ n >>= 1; // Right shift n to move on to the next bit
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
new file mode 100644
index 000000000000..624a4e2b858a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleBitOperations.java
@@ -0,0 +1,68 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class for performing single-bit operations on integers.
+ * These operations include flipping, setting, clearing, and getting
+ * individual bits at specified positions.
+ *
+ * Bit positions are zero-indexed (i.e., the least significant bit is at position 0).
+ * These methods leverage bitwise operations for optimal performance.
+ *
+ * Examples:
+ * - `flipBit(3, 1)` flips the bit at index 1 in binary `11` (result: `1`).
+ * - `setBit(4, 0)` sets the bit at index 0 in `100` (result: `101` or 5).
+ * - `clearBit(7, 1)` clears the bit at index 1 in `111` (result: `101` or 5).
+ * - `getBit(6, 0)` checks if the least significant bit is set (result: `0`).
+ *
+ * Time Complexity: O(1) for all operations.
+ *
+ * Author: lukasb1b (https://github.com/lukasb1b)
+ */
+public final class SingleBitOperations {
+ private SingleBitOperations() {
+ }
+
+ /**
+ * Flips (toggles) the bit at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to flip (0-indexed)
+ * @return the new number after flipping the specified bit
+ */
+ public static int flipBit(final int num, final int bit) {
+ return num ^ (1 << bit);
+ }
+
+ /**
+ * Sets the bit at the specified position to 1.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to set (0-indexed)
+ * @return the new number after setting the specified bit to 1
+ */
+ public static int setBit(final int num, final int bit) {
+ return num | (1 << bit);
+ }
+
+ /**
+ * Clears the bit at the specified position (sets it to 0).
+ *
+ * @param num the input number
+ * @param bit the position of the bit to clear (0-indexed)
+ * @return the new number after clearing the specified bit
+ */
+ public static int clearBit(final int num, final int bit) {
+ return num & ~(1 << bit);
+ }
+
+ /**
+ * Gets the bit value (0 or 1) at the specified position.
+ *
+ * @param num the input number
+ * @param bit the position of the bit to retrieve (0-indexed)
+ * @return 1 if the bit is set, 0 otherwise
+ */
+ public static int getBit(final int num, final int bit) {
+ return (num >> bit) & 1;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
new file mode 100644
index 000000000000..85ebdf02db25
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SingleElement.java
@@ -0,0 +1,39 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * Utility class to find the single non-duplicate element from an array
+ * where all other elements appear twice.
+ *
+ * The algorithm runs in O(n) time complexity and O(1) space complexity
+ * using bitwise XOR.
+ *
+ *
+ * @author Tuhin M
+ */
+public final class SingleElement {
+
+ /**
+ * Private constructor to prevent instantiation of this utility class.
+ * Throws an UnsupportedOperationException if attempted.
+ */
+ private SingleElement() {
+ throw new UnsupportedOperationException("Utility Class");
+ }
+
+ /**
+ * Finds the single non-duplicate element in an array where every other
+ * element appears exactly twice. Uses bitwise XOR to achieve O(n) time
+ * complexity and O(1) space complexity.
+ *
+ * @param arr the input array containing integers where every element
+ * except one appears exactly twice
+ * @return the single non-duplicate element
+ */
+ public static int findSingleElement(int[] arr) {
+ int ele = 0;
+ for (int i = 0; i < arr.length; i++) {
+ ele ^= arr[i];
+ }
+ return ele;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
new file mode 100644
index 000000000000..98a7de8bdf1a
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/SwapAdjacentBits.java
@@ -0,0 +1,57 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * A utility class to swap every pair of adjacent bits in a given integer.
+ * This operation shifts the even-positioned bits to odd positions and vice versa.
+ *
+ * Example:
+ * - Input: 2 (binary: `10`) → Output: 1 (binary: `01`)
+ * - Input: 43 (binary: `101011`) → Output: 23 (binary: `010111`)
+ *
+ * **Explanation of the Algorithm:**
+ * 1. Mask even-positioned bits: Using `0xAAAAAAAA` (binary: `101010...`),
+ * which selects bits in even positions.
+ * 2. Mask odd-positioned bits: Using `0x55555555` (binary: `010101...`),
+ * which selects bits in odd positions.
+ * 3. Shift bits:
+ * - Right-shift even-positioned bits by 1 to move them to odd positions.
+ * - Left-shift odd-positioned bits by 1 to move them to even positions.
+ * 4. Combine both shifted results using bitwise OR (`|`) to produce the final result.
+ *
+ * Use Case: This algorithm can be useful in applications involving low-level bit manipulation,
+ * such as encoding, data compression, or cryptographic transformations.
+ *
+ * Time Complexity: O(1) (constant time, since operations are bitwise).
+ *
+ * Author: Lakshyajeet Singh Goyal (https://github.com/DarkMatter-999)
+ */
+public final class SwapAdjacentBits {
+ private SwapAdjacentBits() {
+ }
+
+ /**
+ * Swaps every pair of adjacent bits of a given integer.
+ * Steps:
+ * 1. Mask the even-positioned bits.
+ * 2. Mask the odd-positioned bits.
+ * 3. Shift the even bits to the right and the odd bits to the left.
+ * 4. Combine the shifted bits.
+ *
+ * @param num the integer whose bits are to be swapped
+ * @return the integer after swapping every pair of adjacent bits
+ */
+ public static int swapAdjacentBits(int num) {
+ // mask the even bits (0xAAAAAAAA => 10101010...)
+ int evenBits = num & 0xAAAAAAAA;
+
+ // mask the odd bits (0x55555555 => 01010101...)
+ int oddBits = num & 0x55555555;
+
+ // right shift even bits and left shift odd bits
+ evenBits >>= 1;
+ oddBits <<= 1;
+
+ // combine shifted bits
+ return evenBits | oddBits;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
new file mode 100644
index 000000000000..9b8cecd791a6
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/TwosComplement.java
@@ -0,0 +1,62 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides a method to compute the Two's Complement of a given binary number.
+ *
+ * In two's complement representation, a binary number's negative value is obtained
+ * by taking the one's complement (inverting all bits) and then adding 1 to the result.
+ * This method handles both small and large binary strings and ensures the output is
+ * correct for all binary inputs, including edge cases like all zeroes and all ones.
+ *
+ *
For more information on Two's Complement:
+ * @see Wikipedia - Two's Complement
+ *
+ *
Algorithm originally suggested by Jon von Neumann.
+ *
+ * @author Abhinay Verma (https://github.com/Monk-AbhinayVerma)
+ */
+public final class TwosComplement {
+ private TwosComplement() {
+ }
+
+ /**
+ * Computes the Two's Complement of the given binary string.
+ * Steps:
+ * 1. Compute the One's Complement (invert all bits).
+ * 2. Add 1 to the One's Complement to get the Two's Complement.
+ * 3. Iterate from the rightmost bit to the left, adding 1 and carrying over as needed.
+ * 4. If a carry is still present after the leftmost bit, prepend '1' to handle overflow.
+ *
+ * @param binary The binary number as a string (only '0' and '1' characters allowed).
+ * @return The two's complement of the input binary string as a new binary string.
+ * @throws IllegalArgumentException If the input contains non-binary characters.
+ */
+ public static String twosComplement(String binary) {
+ if (!binary.matches("[01]+")) {
+ throw new IllegalArgumentException("Input must contain only '0' and '1'.");
+ }
+
+ StringBuilder onesComplement = new StringBuilder();
+ for (char bit : binary.toCharArray()) {
+ onesComplement.append(bit == '0' ? '1' : '0');
+ }
+
+ StringBuilder twosComplement = new StringBuilder(onesComplement);
+ boolean carry = true;
+
+ for (int i = onesComplement.length() - 1; i >= 0 && carry; i--) {
+ if (onesComplement.charAt(i) == '1') {
+ twosComplement.setCharAt(i, '0');
+ } else {
+ twosComplement.setCharAt(i, '1');
+ carry = false;
+ }
+ }
+
+ if (carry) {
+ twosComplement.insert(0, '1');
+ }
+
+ return twosComplement.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java b/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java
new file mode 100644
index 000000000000..b22abc0c04ff
--- /dev/null
+++ b/src/main/java/com/thealgorithms/bitmanipulation/Xs3Conversion.java
@@ -0,0 +1,58 @@
+package com.thealgorithms.bitmanipulation;
+
+/**
+ * This class provides methods to convert between XS-3 (Excess-3) and binary.
+ *
+ * Excess-3, also called XS-3, is a binary-coded decimal (BCD) code in which each decimal digit is represented by its corresponding 4-bit binary value plus 3.
+ *
+ * For more information, refer to the
+ * Excess-3 Wikipedia page.
+ *
+ * Example usage:
+ *
+ * int binary = Xs3Conversion.xs3ToBinary(0x4567);
+ * System.out.println("XS-3 0x4567 to binary: " + binary); // Output: 1234
+ *
+ * int xs3 = Xs3Conversion.binaryToXs3(1234);
+ * System.out.println("Binary 1234 to XS-3: " + Integer.toHexString(xs3)); // Output: 0x4567
+ *
+ */
+public final class Xs3Conversion {
+ private Xs3Conversion() {
+ }
+ /**
+ * Converts an XS-3 (Excess-3) number to binary.
+ *
+ * @param xs3 The XS-3 number.
+ * @return The corresponding binary number.
+ */
+ public static int xs3ToBinary(int xs3) {
+ int binary = 0;
+ int multiplier = 1;
+ while (xs3 > 0) {
+ int digit = (xs3 & 0xF) - 3; // Extract the last 4 bits (one XS-3 digit) and subtract 3
+ binary += digit * multiplier;
+ multiplier *= 10;
+ xs3 >>= 4; // Shift right by 4 bits to process the next XS-3 digit
+ }
+ return binary;
+ }
+
+ /**
+ * Converts a binary number to XS-3 (Excess-3).
+ *
+ * @param binary The binary number.
+ * @return The corresponding XS-3 number.
+ */
+ public static int binaryToXs3(int binary) {
+ int xs3 = 0;
+ int shift = 0;
+ while (binary > 0) {
+ int digit = (binary % 10) + 3; // Extract the last decimal digit and add 3
+ xs3 |= (digit << (shift * 4)); // Shift the digit to the correct XS-3 position
+ binary /= 10; // Remove the last decimal digit
+ shift++;
+ }
+ return xs3;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
new file mode 100644
index 000000000000..d915858f9e6f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/ADFGVXCipher.java
@@ -0,0 +1,167 @@
+package com.thealgorithms.ciphers;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The ADFGVX cipher is a fractionating transposition cipher that was used by
+ * the German Army during World War I. It combines a **Polybius square substitution**
+ * with a **columnar transposition** to enhance encryption strength.
+ *
+ * The name "ADFGVX" refers to the six letters (A, D, F, G, V, X) used as row and
+ * column labels in the Polybius square. This cipher was designed to secure
+ * communication and create complex, hard-to-break ciphertexts.
+ *
+ * Learn more: ADFGVX Cipher - Wikipedia.
+ *
+ * Example usage:
+ *
+ * ADFGVXCipher cipher = new ADFGVXCipher();
+ * String encrypted = cipher.encrypt("attack at 1200am", "PRIVACY");
+ * String decrypted = cipher.decrypt(encrypted, "PRIVACY");
+ *
+ *
+ * @author bennybebo
+ */
+public class ADFGVXCipher {
+
+ // Constants used in the Polybius square
+ private static final char[] POLYBIUS_LETTERS = {'A', 'D', 'F', 'G', 'V', 'X'};
+ 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'}};
+
+ // Maps for fast substitution lookups
+ private static final Map POLYBIUS_MAP = new HashMap<>();
+ private static final Map REVERSE_POLYBIUS_MAP = new HashMap<>();
+
+ // Static block to initialize the lookup tables from the Polybius square
+ static {
+ for (int i = 0; i < POLYBIUS_SQUARE.length; i++) {
+ for (int j = 0; j < POLYBIUS_SQUARE[i].length; j++) {
+ String key = "" + POLYBIUS_LETTERS[i] + POLYBIUS_LETTERS[j];
+ POLYBIUS_MAP.put(key, POLYBIUS_SQUARE[i][j]);
+ REVERSE_POLYBIUS_MAP.put(POLYBIUS_SQUARE[i][j], key);
+ }
+ }
+ }
+
+ /**
+ * Encrypts a given plaintext using the ADFGVX cipher with the provided keyword.
+ * Steps:
+ * 1. Substitute each letter in the plaintext with a pair of ADFGVX letters.
+ * 2. Perform a columnar transposition on the fractionated text using the keyword.
+ *
+ * @param plaintext The message to be encrypted (can contain letters and digits).
+ * @param key The keyword for columnar transposition.
+ * @return The encrypted message as ciphertext.
+ */
+ public String encrypt(String plaintext, String key) {
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z0-9]", ""); // Sanitize input
+ StringBuilder fractionatedText = new StringBuilder();
+
+ for (char c : plaintext.toCharArray()) {
+ fractionatedText.append(REVERSE_POLYBIUS_MAP.get(c));
+ }
+
+ return columnarTransposition(fractionatedText.toString(), key);
+ }
+
+ /**
+ * Decrypts a given ciphertext using the ADFGVX cipher with the provided keyword.
+ * Steps:
+ * 1. Reverse the columnar transposition performed during encryption.
+ * 2. Substitute each pair of ADFGVX letters with the corresponding plaintext letter.
+ * The resulting text is the decrypted message.
+ *
+ * @param ciphertext The encrypted message.
+ * @param key The keyword used during encryption.
+ * @return The decrypted plaintext message.
+ */
+ public String decrypt(String ciphertext, String key) {
+ String fractionatedText = reverseColumnarTransposition(ciphertext, key);
+
+ StringBuilder plaintext = new StringBuilder();
+ for (int i = 0; i < fractionatedText.length(); i += 2) {
+ String pair = fractionatedText.substring(i, i + 2);
+ plaintext.append(POLYBIUS_MAP.get(pair));
+ }
+
+ return plaintext.toString();
+ }
+
+ /**
+ * Helper method: Performs columnar transposition during encryption
+ *
+ * @param text The fractionated text to be transposed
+ * @param key The keyword for columnar transposition
+ * @return The transposed text
+ */
+ private String columnarTransposition(String text, String key) {
+ int numRows = (int) Math.ceil((double) text.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+ for (char[] row : table) { // Fill empty cells with underscores
+ Arrays.fill(row, '_');
+ }
+
+ // Populate the table row by row
+ for (int i = 0; i < text.length(); i++) {
+ table[i / key.length()][i % key.length()] = text.charAt(i);
+ }
+
+ // Read columns based on the alphabetical order of the key
+ StringBuilder ciphertext = new StringBuilder();
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (char[] row : table) {
+ if (row[column] != '_') {
+ ciphertext.append(row[column]);
+ }
+ }
+ }
+
+ return ciphertext.toString();
+ }
+
+ /**
+ * Helper method: Reverses the columnar transposition during decryption
+ *
+ * @param ciphertext The transposed text to be reversed
+ * @param key The keyword used during encryption
+ * @return The reversed text
+ */
+ private String reverseColumnarTransposition(String ciphertext, String key) {
+ int numRows = (int) Math.ceil((double) ciphertext.length() / key.length());
+ char[][] table = new char[numRows][key.length()];
+
+ char[] sortedKey = key.toCharArray();
+ Arrays.sort(sortedKey);
+
+ int index = 0;
+ // Populate the table column by column according to the sorted key
+ for (char keyChar : sortedKey) {
+ int column = key.indexOf(keyChar);
+ for (int row = 0; row < numRows; row++) {
+ if (index < ciphertext.length()) {
+ table[row][column] = ciphertext.charAt(index++);
+ } else {
+ table[row][column] = '_';
+ }
+ }
+ }
+
+ // Read the table row by row to reconstruct the fractionated text
+ StringBuilder fractionatedText = new StringBuilder();
+ for (char[] row : table) {
+ for (char cell : row) {
+ if (cell != '_') {
+ fractionatedText.append(cell);
+ }
+ }
+ }
+
+ return fractionatedText.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AES.java b/src/main/java/com/thealgorithms/ciphers/AES.java
new file mode 100644
index 000000000000..df51eba55310
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AES.java
@@ -0,0 +1,2781 @@
+package com.thealgorithms.ciphers;
+
+import java.math.BigInteger;
+import java.util.Scanner;
+
+/**
+ * This class is build to demonstrate the application of the AES-algorithm on a
+ * single 128-Bit block of data.
+ */
+public final class AES {
+ private AES() {
+ }
+
+ /**
+ * Precalculated values for x to the power of 2 in Rijndaels galois field.
+ * Used as 'RCON' during the key expansion.
+ */
+ private static final int[] RCON = {
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+ 0x5e,
+ 0xbc,
+ 0x63,
+ 0xc6,
+ 0x97,
+ 0x35,
+ 0x6a,
+ 0xd4,
+ 0xb3,
+ 0x7d,
+ 0xfa,
+ 0xef,
+ 0xc5,
+ 0x91,
+ 0x39,
+ 0x72,
+ 0xe4,
+ 0xd3,
+ 0xbd,
+ 0x61,
+ 0xc2,
+ 0x9f,
+ 0x25,
+ 0x4a,
+ 0x94,
+ 0x33,
+ 0x66,
+ 0xcc,
+ 0x83,
+ 0x1d,
+ 0x3a,
+ 0x74,
+ 0xe8,
+ 0xcb,
+ 0x8d,
+ };
+
+ /**
+ * Rijndael S-box Substitution table used for encryption in the subBytes
+ * step, as well as the key expansion.
+ */
+ private static final int[] SBOX = {
+ 0x63,
+ 0x7C,
+ 0x77,
+ 0x7B,
+ 0xF2,
+ 0x6B,
+ 0x6F,
+ 0xC5,
+ 0x30,
+ 0x01,
+ 0x67,
+ 0x2B,
+ 0xFE,
+ 0xD7,
+ 0xAB,
+ 0x76,
+ 0xCA,
+ 0x82,
+ 0xC9,
+ 0x7D,
+ 0xFA,
+ 0x59,
+ 0x47,
+ 0xF0,
+ 0xAD,
+ 0xD4,
+ 0xA2,
+ 0xAF,
+ 0x9C,
+ 0xA4,
+ 0x72,
+ 0xC0,
+ 0xB7,
+ 0xFD,
+ 0x93,
+ 0x26,
+ 0x36,
+ 0x3F,
+ 0xF7,
+ 0xCC,
+ 0x34,
+ 0xA5,
+ 0xE5,
+ 0xF1,
+ 0x71,
+ 0xD8,
+ 0x31,
+ 0x15,
+ 0x04,
+ 0xC7,
+ 0x23,
+ 0xC3,
+ 0x18,
+ 0x96,
+ 0x05,
+ 0x9A,
+ 0x07,
+ 0x12,
+ 0x80,
+ 0xE2,
+ 0xEB,
+ 0x27,
+ 0xB2,
+ 0x75,
+ 0x09,
+ 0x83,
+ 0x2C,
+ 0x1A,
+ 0x1B,
+ 0x6E,
+ 0x5A,
+ 0xA0,
+ 0x52,
+ 0x3B,
+ 0xD6,
+ 0xB3,
+ 0x29,
+ 0xE3,
+ 0x2F,
+ 0x84,
+ 0x53,
+ 0xD1,
+ 0x00,
+ 0xED,
+ 0x20,
+ 0xFC,
+ 0xB1,
+ 0x5B,
+ 0x6A,
+ 0xCB,
+ 0xBE,
+ 0x39,
+ 0x4A,
+ 0x4C,
+ 0x58,
+ 0xCF,
+ 0xD0,
+ 0xEF,
+ 0xAA,
+ 0xFB,
+ 0x43,
+ 0x4D,
+ 0x33,
+ 0x85,
+ 0x45,
+ 0xF9,
+ 0x02,
+ 0x7F,
+ 0x50,
+ 0x3C,
+ 0x9F,
+ 0xA8,
+ 0x51,
+ 0xA3,
+ 0x40,
+ 0x8F,
+ 0x92,
+ 0x9D,
+ 0x38,
+ 0xF5,
+ 0xBC,
+ 0xB6,
+ 0xDA,
+ 0x21,
+ 0x10,
+ 0xFF,
+ 0xF3,
+ 0xD2,
+ 0xCD,
+ 0x0C,
+ 0x13,
+ 0xEC,
+ 0x5F,
+ 0x97,
+ 0x44,
+ 0x17,
+ 0xC4,
+ 0xA7,
+ 0x7E,
+ 0x3D,
+ 0x64,
+ 0x5D,
+ 0x19,
+ 0x73,
+ 0x60,
+ 0x81,
+ 0x4F,
+ 0xDC,
+ 0x22,
+ 0x2A,
+ 0x90,
+ 0x88,
+ 0x46,
+ 0xEE,
+ 0xB8,
+ 0x14,
+ 0xDE,
+ 0x5E,
+ 0x0B,
+ 0xDB,
+ 0xE0,
+ 0x32,
+ 0x3A,
+ 0x0A,
+ 0x49,
+ 0x06,
+ 0x24,
+ 0x5C,
+ 0xC2,
+ 0xD3,
+ 0xAC,
+ 0x62,
+ 0x91,
+ 0x95,
+ 0xE4,
+ 0x79,
+ 0xE7,
+ 0xC8,
+ 0x37,
+ 0x6D,
+ 0x8D,
+ 0xD5,
+ 0x4E,
+ 0xA9,
+ 0x6C,
+ 0x56,
+ 0xF4,
+ 0xEA,
+ 0x65,
+ 0x7A,
+ 0xAE,
+ 0x08,
+ 0xBA,
+ 0x78,
+ 0x25,
+ 0x2E,
+ 0x1C,
+ 0xA6,
+ 0xB4,
+ 0xC6,
+ 0xE8,
+ 0xDD,
+ 0x74,
+ 0x1F,
+ 0x4B,
+ 0xBD,
+ 0x8B,
+ 0x8A,
+ 0x70,
+ 0x3E,
+ 0xB5,
+ 0x66,
+ 0x48,
+ 0x03,
+ 0xF6,
+ 0x0E,
+ 0x61,
+ 0x35,
+ 0x57,
+ 0xB9,
+ 0x86,
+ 0xC1,
+ 0x1D,
+ 0x9E,
+ 0xE1,
+ 0xF8,
+ 0x98,
+ 0x11,
+ 0x69,
+ 0xD9,
+ 0x8E,
+ 0x94,
+ 0x9B,
+ 0x1E,
+ 0x87,
+ 0xE9,
+ 0xCE,
+ 0x55,
+ 0x28,
+ 0xDF,
+ 0x8C,
+ 0xA1,
+ 0x89,
+ 0x0D,
+ 0xBF,
+ 0xE6,
+ 0x42,
+ 0x68,
+ 0x41,
+ 0x99,
+ 0x2D,
+ 0x0F,
+ 0xB0,
+ 0x54,
+ 0xBB,
+ 0x16,
+ };
+
+ /**
+ * Inverse Rijndael S-box Substitution table used for decryption in the
+ * subBytesDec step.
+ */
+ private static final int[] INVERSE_SBOX = {
+ 0x52,
+ 0x09,
+ 0x6A,
+ 0xD5,
+ 0x30,
+ 0x36,
+ 0xA5,
+ 0x38,
+ 0xBF,
+ 0x40,
+ 0xA3,
+ 0x9E,
+ 0x81,
+ 0xF3,
+ 0xD7,
+ 0xFB,
+ 0x7C,
+ 0xE3,
+ 0x39,
+ 0x82,
+ 0x9B,
+ 0x2F,
+ 0xFF,
+ 0x87,
+ 0x34,
+ 0x8E,
+ 0x43,
+ 0x44,
+ 0xC4,
+ 0xDE,
+ 0xE9,
+ 0xCB,
+ 0x54,
+ 0x7B,
+ 0x94,
+ 0x32,
+ 0xA6,
+ 0xC2,
+ 0x23,
+ 0x3D,
+ 0xEE,
+ 0x4C,
+ 0x95,
+ 0x0B,
+ 0x42,
+ 0xFA,
+ 0xC3,
+ 0x4E,
+ 0x08,
+ 0x2E,
+ 0xA1,
+ 0x66,
+ 0x28,
+ 0xD9,
+ 0x24,
+ 0xB2,
+ 0x76,
+ 0x5B,
+ 0xA2,
+ 0x49,
+ 0x6D,
+ 0x8B,
+ 0xD1,
+ 0x25,
+ 0x72,
+ 0xF8,
+ 0xF6,
+ 0x64,
+ 0x86,
+ 0x68,
+ 0x98,
+ 0x16,
+ 0xD4,
+ 0xA4,
+ 0x5C,
+ 0xCC,
+ 0x5D,
+ 0x65,
+ 0xB6,
+ 0x92,
+ 0x6C,
+ 0x70,
+ 0x48,
+ 0x50,
+ 0xFD,
+ 0xED,
+ 0xB9,
+ 0xDA,
+ 0x5E,
+ 0x15,
+ 0x46,
+ 0x57,
+ 0xA7,
+ 0x8D,
+ 0x9D,
+ 0x84,
+ 0x90,
+ 0xD8,
+ 0xAB,
+ 0x00,
+ 0x8C,
+ 0xBC,
+ 0xD3,
+ 0x0A,
+ 0xF7,
+ 0xE4,
+ 0x58,
+ 0x05,
+ 0xB8,
+ 0xB3,
+ 0x45,
+ 0x06,
+ 0xD0,
+ 0x2C,
+ 0x1E,
+ 0x8F,
+ 0xCA,
+ 0x3F,
+ 0x0F,
+ 0x02,
+ 0xC1,
+ 0xAF,
+ 0xBD,
+ 0x03,
+ 0x01,
+ 0x13,
+ 0x8A,
+ 0x6B,
+ 0x3A,
+ 0x91,
+ 0x11,
+ 0x41,
+ 0x4F,
+ 0x67,
+ 0xDC,
+ 0xEA,
+ 0x97,
+ 0xF2,
+ 0xCF,
+ 0xCE,
+ 0xF0,
+ 0xB4,
+ 0xE6,
+ 0x73,
+ 0x96,
+ 0xAC,
+ 0x74,
+ 0x22,
+ 0xE7,
+ 0xAD,
+ 0x35,
+ 0x85,
+ 0xE2,
+ 0xF9,
+ 0x37,
+ 0xE8,
+ 0x1C,
+ 0x75,
+ 0xDF,
+ 0x6E,
+ 0x47,
+ 0xF1,
+ 0x1A,
+ 0x71,
+ 0x1D,
+ 0x29,
+ 0xC5,
+ 0x89,
+ 0x6F,
+ 0xB7,
+ 0x62,
+ 0x0E,
+ 0xAA,
+ 0x18,
+ 0xBE,
+ 0x1B,
+ 0xFC,
+ 0x56,
+ 0x3E,
+ 0x4B,
+ 0xC6,
+ 0xD2,
+ 0x79,
+ 0x20,
+ 0x9A,
+ 0xDB,
+ 0xC0,
+ 0xFE,
+ 0x78,
+ 0xCD,
+ 0x5A,
+ 0xF4,
+ 0x1F,
+ 0xDD,
+ 0xA8,
+ 0x33,
+ 0x88,
+ 0x07,
+ 0xC7,
+ 0x31,
+ 0xB1,
+ 0x12,
+ 0x10,
+ 0x59,
+ 0x27,
+ 0x80,
+ 0xEC,
+ 0x5F,
+ 0x60,
+ 0x51,
+ 0x7F,
+ 0xA9,
+ 0x19,
+ 0xB5,
+ 0x4A,
+ 0x0D,
+ 0x2D,
+ 0xE5,
+ 0x7A,
+ 0x9F,
+ 0x93,
+ 0xC9,
+ 0x9C,
+ 0xEF,
+ 0xA0,
+ 0xE0,
+ 0x3B,
+ 0x4D,
+ 0xAE,
+ 0x2A,
+ 0xF5,
+ 0xB0,
+ 0xC8,
+ 0xEB,
+ 0xBB,
+ 0x3C,
+ 0x83,
+ 0x53,
+ 0x99,
+ 0x61,
+ 0x17,
+ 0x2B,
+ 0x04,
+ 0x7E,
+ 0xBA,
+ 0x77,
+ 0xD6,
+ 0x26,
+ 0xE1,
+ 0x69,
+ 0x14,
+ 0x63,
+ 0x55,
+ 0x21,
+ 0x0C,
+ 0x7D,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 2 used in
+ * the MixColums step during encryption.
+ */
+ private static final int[] MULT2 = {
+ 0x00,
+ 0x02,
+ 0x04,
+ 0x06,
+ 0x08,
+ 0x0a,
+ 0x0c,
+ 0x0e,
+ 0x10,
+ 0x12,
+ 0x14,
+ 0x16,
+ 0x18,
+ 0x1a,
+ 0x1c,
+ 0x1e,
+ 0x20,
+ 0x22,
+ 0x24,
+ 0x26,
+ 0x28,
+ 0x2a,
+ 0x2c,
+ 0x2e,
+ 0x30,
+ 0x32,
+ 0x34,
+ 0x36,
+ 0x38,
+ 0x3a,
+ 0x3c,
+ 0x3e,
+ 0x40,
+ 0x42,
+ 0x44,
+ 0x46,
+ 0x48,
+ 0x4a,
+ 0x4c,
+ 0x4e,
+ 0x50,
+ 0x52,
+ 0x54,
+ 0x56,
+ 0x58,
+ 0x5a,
+ 0x5c,
+ 0x5e,
+ 0x60,
+ 0x62,
+ 0x64,
+ 0x66,
+ 0x68,
+ 0x6a,
+ 0x6c,
+ 0x6e,
+ 0x70,
+ 0x72,
+ 0x74,
+ 0x76,
+ 0x78,
+ 0x7a,
+ 0x7c,
+ 0x7e,
+ 0x80,
+ 0x82,
+ 0x84,
+ 0x86,
+ 0x88,
+ 0x8a,
+ 0x8c,
+ 0x8e,
+ 0x90,
+ 0x92,
+ 0x94,
+ 0x96,
+ 0x98,
+ 0x9a,
+ 0x9c,
+ 0x9e,
+ 0xa0,
+ 0xa2,
+ 0xa4,
+ 0xa6,
+ 0xa8,
+ 0xaa,
+ 0xac,
+ 0xae,
+ 0xb0,
+ 0xb2,
+ 0xb4,
+ 0xb6,
+ 0xb8,
+ 0xba,
+ 0xbc,
+ 0xbe,
+ 0xc0,
+ 0xc2,
+ 0xc4,
+ 0xc6,
+ 0xc8,
+ 0xca,
+ 0xcc,
+ 0xce,
+ 0xd0,
+ 0xd2,
+ 0xd4,
+ 0xd6,
+ 0xd8,
+ 0xda,
+ 0xdc,
+ 0xde,
+ 0xe0,
+ 0xe2,
+ 0xe4,
+ 0xe6,
+ 0xe8,
+ 0xea,
+ 0xec,
+ 0xee,
+ 0xf0,
+ 0xf2,
+ 0xf4,
+ 0xf6,
+ 0xf8,
+ 0xfa,
+ 0xfc,
+ 0xfe,
+ 0x1b,
+ 0x19,
+ 0x1f,
+ 0x1d,
+ 0x13,
+ 0x11,
+ 0x17,
+ 0x15,
+ 0x0b,
+ 0x09,
+ 0x0f,
+ 0x0d,
+ 0x03,
+ 0x01,
+ 0x07,
+ 0x05,
+ 0x3b,
+ 0x39,
+ 0x3f,
+ 0x3d,
+ 0x33,
+ 0x31,
+ 0x37,
+ 0x35,
+ 0x2b,
+ 0x29,
+ 0x2f,
+ 0x2d,
+ 0x23,
+ 0x21,
+ 0x27,
+ 0x25,
+ 0x5b,
+ 0x59,
+ 0x5f,
+ 0x5d,
+ 0x53,
+ 0x51,
+ 0x57,
+ 0x55,
+ 0x4b,
+ 0x49,
+ 0x4f,
+ 0x4d,
+ 0x43,
+ 0x41,
+ 0x47,
+ 0x45,
+ 0x7b,
+ 0x79,
+ 0x7f,
+ 0x7d,
+ 0x73,
+ 0x71,
+ 0x77,
+ 0x75,
+ 0x6b,
+ 0x69,
+ 0x6f,
+ 0x6d,
+ 0x63,
+ 0x61,
+ 0x67,
+ 0x65,
+ 0x9b,
+ 0x99,
+ 0x9f,
+ 0x9d,
+ 0x93,
+ 0x91,
+ 0x97,
+ 0x95,
+ 0x8b,
+ 0x89,
+ 0x8f,
+ 0x8d,
+ 0x83,
+ 0x81,
+ 0x87,
+ 0x85,
+ 0xbb,
+ 0xb9,
+ 0xbf,
+ 0xbd,
+ 0xb3,
+ 0xb1,
+ 0xb7,
+ 0xb5,
+ 0xab,
+ 0xa9,
+ 0xaf,
+ 0xad,
+ 0xa3,
+ 0xa1,
+ 0xa7,
+ 0xa5,
+ 0xdb,
+ 0xd9,
+ 0xdf,
+ 0xdd,
+ 0xd3,
+ 0xd1,
+ 0xd7,
+ 0xd5,
+ 0xcb,
+ 0xc9,
+ 0xcf,
+ 0xcd,
+ 0xc3,
+ 0xc1,
+ 0xc7,
+ 0xc5,
+ 0xfb,
+ 0xf9,
+ 0xff,
+ 0xfd,
+ 0xf3,
+ 0xf1,
+ 0xf7,
+ 0xf5,
+ 0xeb,
+ 0xe9,
+ 0xef,
+ 0xed,
+ 0xe3,
+ 0xe1,
+ 0xe7,
+ 0xe5,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 3 used in
+ * the MixColums step during encryption.
+ */
+ private static final int[] MULT3 = {
+ 0x00,
+ 0x03,
+ 0x06,
+ 0x05,
+ 0x0c,
+ 0x0f,
+ 0x0a,
+ 0x09,
+ 0x18,
+ 0x1b,
+ 0x1e,
+ 0x1d,
+ 0x14,
+ 0x17,
+ 0x12,
+ 0x11,
+ 0x30,
+ 0x33,
+ 0x36,
+ 0x35,
+ 0x3c,
+ 0x3f,
+ 0x3a,
+ 0x39,
+ 0x28,
+ 0x2b,
+ 0x2e,
+ 0x2d,
+ 0x24,
+ 0x27,
+ 0x22,
+ 0x21,
+ 0x60,
+ 0x63,
+ 0x66,
+ 0x65,
+ 0x6c,
+ 0x6f,
+ 0x6a,
+ 0x69,
+ 0x78,
+ 0x7b,
+ 0x7e,
+ 0x7d,
+ 0x74,
+ 0x77,
+ 0x72,
+ 0x71,
+ 0x50,
+ 0x53,
+ 0x56,
+ 0x55,
+ 0x5c,
+ 0x5f,
+ 0x5a,
+ 0x59,
+ 0x48,
+ 0x4b,
+ 0x4e,
+ 0x4d,
+ 0x44,
+ 0x47,
+ 0x42,
+ 0x41,
+ 0xc0,
+ 0xc3,
+ 0xc6,
+ 0xc5,
+ 0xcc,
+ 0xcf,
+ 0xca,
+ 0xc9,
+ 0xd8,
+ 0xdb,
+ 0xde,
+ 0xdd,
+ 0xd4,
+ 0xd7,
+ 0xd2,
+ 0xd1,
+ 0xf0,
+ 0xf3,
+ 0xf6,
+ 0xf5,
+ 0xfc,
+ 0xff,
+ 0xfa,
+ 0xf9,
+ 0xe8,
+ 0xeb,
+ 0xee,
+ 0xed,
+ 0xe4,
+ 0xe7,
+ 0xe2,
+ 0xe1,
+ 0xa0,
+ 0xa3,
+ 0xa6,
+ 0xa5,
+ 0xac,
+ 0xaf,
+ 0xaa,
+ 0xa9,
+ 0xb8,
+ 0xbb,
+ 0xbe,
+ 0xbd,
+ 0xb4,
+ 0xb7,
+ 0xb2,
+ 0xb1,
+ 0x90,
+ 0x93,
+ 0x96,
+ 0x95,
+ 0x9c,
+ 0x9f,
+ 0x9a,
+ 0x99,
+ 0x88,
+ 0x8b,
+ 0x8e,
+ 0x8d,
+ 0x84,
+ 0x87,
+ 0x82,
+ 0x81,
+ 0x9b,
+ 0x98,
+ 0x9d,
+ 0x9e,
+ 0x97,
+ 0x94,
+ 0x91,
+ 0x92,
+ 0x83,
+ 0x80,
+ 0x85,
+ 0x86,
+ 0x8f,
+ 0x8c,
+ 0x89,
+ 0x8a,
+ 0xab,
+ 0xa8,
+ 0xad,
+ 0xae,
+ 0xa7,
+ 0xa4,
+ 0xa1,
+ 0xa2,
+ 0xb3,
+ 0xb0,
+ 0xb5,
+ 0xb6,
+ 0xbf,
+ 0xbc,
+ 0xb9,
+ 0xba,
+ 0xfb,
+ 0xf8,
+ 0xfd,
+ 0xfe,
+ 0xf7,
+ 0xf4,
+ 0xf1,
+ 0xf2,
+ 0xe3,
+ 0xe0,
+ 0xe5,
+ 0xe6,
+ 0xef,
+ 0xec,
+ 0xe9,
+ 0xea,
+ 0xcb,
+ 0xc8,
+ 0xcd,
+ 0xce,
+ 0xc7,
+ 0xc4,
+ 0xc1,
+ 0xc2,
+ 0xd3,
+ 0xd0,
+ 0xd5,
+ 0xd6,
+ 0xdf,
+ 0xdc,
+ 0xd9,
+ 0xda,
+ 0x5b,
+ 0x58,
+ 0x5d,
+ 0x5e,
+ 0x57,
+ 0x54,
+ 0x51,
+ 0x52,
+ 0x43,
+ 0x40,
+ 0x45,
+ 0x46,
+ 0x4f,
+ 0x4c,
+ 0x49,
+ 0x4a,
+ 0x6b,
+ 0x68,
+ 0x6d,
+ 0x6e,
+ 0x67,
+ 0x64,
+ 0x61,
+ 0x62,
+ 0x73,
+ 0x70,
+ 0x75,
+ 0x76,
+ 0x7f,
+ 0x7c,
+ 0x79,
+ 0x7a,
+ 0x3b,
+ 0x38,
+ 0x3d,
+ 0x3e,
+ 0x37,
+ 0x34,
+ 0x31,
+ 0x32,
+ 0x23,
+ 0x20,
+ 0x25,
+ 0x26,
+ 0x2f,
+ 0x2c,
+ 0x29,
+ 0x2a,
+ 0x0b,
+ 0x08,
+ 0x0d,
+ 0x0e,
+ 0x07,
+ 0x04,
+ 0x01,
+ 0x02,
+ 0x13,
+ 0x10,
+ 0x15,
+ 0x16,
+ 0x1f,
+ 0x1c,
+ 0x19,
+ 0x1a,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 9 used in
+ * the MixColums step during decryption.
+ */
+ private static final int[] MULT9 = {
+ 0x00,
+ 0x09,
+ 0x12,
+ 0x1b,
+ 0x24,
+ 0x2d,
+ 0x36,
+ 0x3f,
+ 0x48,
+ 0x41,
+ 0x5a,
+ 0x53,
+ 0x6c,
+ 0x65,
+ 0x7e,
+ 0x77,
+ 0x90,
+ 0x99,
+ 0x82,
+ 0x8b,
+ 0xb4,
+ 0xbd,
+ 0xa6,
+ 0xaf,
+ 0xd8,
+ 0xd1,
+ 0xca,
+ 0xc3,
+ 0xfc,
+ 0xf5,
+ 0xee,
+ 0xe7,
+ 0x3b,
+ 0x32,
+ 0x29,
+ 0x20,
+ 0x1f,
+ 0x16,
+ 0x0d,
+ 0x04,
+ 0x73,
+ 0x7a,
+ 0x61,
+ 0x68,
+ 0x57,
+ 0x5e,
+ 0x45,
+ 0x4c,
+ 0xab,
+ 0xa2,
+ 0xb9,
+ 0xb0,
+ 0x8f,
+ 0x86,
+ 0x9d,
+ 0x94,
+ 0xe3,
+ 0xea,
+ 0xf1,
+ 0xf8,
+ 0xc7,
+ 0xce,
+ 0xd5,
+ 0xdc,
+ 0x76,
+ 0x7f,
+ 0x64,
+ 0x6d,
+ 0x52,
+ 0x5b,
+ 0x40,
+ 0x49,
+ 0x3e,
+ 0x37,
+ 0x2c,
+ 0x25,
+ 0x1a,
+ 0x13,
+ 0x08,
+ 0x01,
+ 0xe6,
+ 0xef,
+ 0xf4,
+ 0xfd,
+ 0xc2,
+ 0xcb,
+ 0xd0,
+ 0xd9,
+ 0xae,
+ 0xa7,
+ 0xbc,
+ 0xb5,
+ 0x8a,
+ 0x83,
+ 0x98,
+ 0x91,
+ 0x4d,
+ 0x44,
+ 0x5f,
+ 0x56,
+ 0x69,
+ 0x60,
+ 0x7b,
+ 0x72,
+ 0x05,
+ 0x0c,
+ 0x17,
+ 0x1e,
+ 0x21,
+ 0x28,
+ 0x33,
+ 0x3a,
+ 0xdd,
+ 0xd4,
+ 0xcf,
+ 0xc6,
+ 0xf9,
+ 0xf0,
+ 0xeb,
+ 0xe2,
+ 0x95,
+ 0x9c,
+ 0x87,
+ 0x8e,
+ 0xb1,
+ 0xb8,
+ 0xa3,
+ 0xaa,
+ 0xec,
+ 0xe5,
+ 0xfe,
+ 0xf7,
+ 0xc8,
+ 0xc1,
+ 0xda,
+ 0xd3,
+ 0xa4,
+ 0xad,
+ 0xb6,
+ 0xbf,
+ 0x80,
+ 0x89,
+ 0x92,
+ 0x9b,
+ 0x7c,
+ 0x75,
+ 0x6e,
+ 0x67,
+ 0x58,
+ 0x51,
+ 0x4a,
+ 0x43,
+ 0x34,
+ 0x3d,
+ 0x26,
+ 0x2f,
+ 0x10,
+ 0x19,
+ 0x02,
+ 0x0b,
+ 0xd7,
+ 0xde,
+ 0xc5,
+ 0xcc,
+ 0xf3,
+ 0xfa,
+ 0xe1,
+ 0xe8,
+ 0x9f,
+ 0x96,
+ 0x8d,
+ 0x84,
+ 0xbb,
+ 0xb2,
+ 0xa9,
+ 0xa0,
+ 0x47,
+ 0x4e,
+ 0x55,
+ 0x5c,
+ 0x63,
+ 0x6a,
+ 0x71,
+ 0x78,
+ 0x0f,
+ 0x06,
+ 0x1d,
+ 0x14,
+ 0x2b,
+ 0x22,
+ 0x39,
+ 0x30,
+ 0x9a,
+ 0x93,
+ 0x88,
+ 0x81,
+ 0xbe,
+ 0xb7,
+ 0xac,
+ 0xa5,
+ 0xd2,
+ 0xdb,
+ 0xc0,
+ 0xc9,
+ 0xf6,
+ 0xff,
+ 0xe4,
+ 0xed,
+ 0x0a,
+ 0x03,
+ 0x18,
+ 0x11,
+ 0x2e,
+ 0x27,
+ 0x3c,
+ 0x35,
+ 0x42,
+ 0x4b,
+ 0x50,
+ 0x59,
+ 0x66,
+ 0x6f,
+ 0x74,
+ 0x7d,
+ 0xa1,
+ 0xa8,
+ 0xb3,
+ 0xba,
+ 0x85,
+ 0x8c,
+ 0x97,
+ 0x9e,
+ 0xe9,
+ 0xe0,
+ 0xfb,
+ 0xf2,
+ 0xcd,
+ 0xc4,
+ 0xdf,
+ 0xd6,
+ 0x31,
+ 0x38,
+ 0x23,
+ 0x2a,
+ 0x15,
+ 0x1c,
+ 0x07,
+ 0x0e,
+ 0x79,
+ 0x70,
+ 0x6b,
+ 0x62,
+ 0x5d,
+ 0x54,
+ 0x4f,
+ 0x46,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 11 used in
+ * the MixColums step during decryption.
+ */
+ private static final int[] MULT11 = {
+ 0x00,
+ 0x0b,
+ 0x16,
+ 0x1d,
+ 0x2c,
+ 0x27,
+ 0x3a,
+ 0x31,
+ 0x58,
+ 0x53,
+ 0x4e,
+ 0x45,
+ 0x74,
+ 0x7f,
+ 0x62,
+ 0x69,
+ 0xb0,
+ 0xbb,
+ 0xa6,
+ 0xad,
+ 0x9c,
+ 0x97,
+ 0x8a,
+ 0x81,
+ 0xe8,
+ 0xe3,
+ 0xfe,
+ 0xf5,
+ 0xc4,
+ 0xcf,
+ 0xd2,
+ 0xd9,
+ 0x7b,
+ 0x70,
+ 0x6d,
+ 0x66,
+ 0x57,
+ 0x5c,
+ 0x41,
+ 0x4a,
+ 0x23,
+ 0x28,
+ 0x35,
+ 0x3e,
+ 0x0f,
+ 0x04,
+ 0x19,
+ 0x12,
+ 0xcb,
+ 0xc0,
+ 0xdd,
+ 0xd6,
+ 0xe7,
+ 0xec,
+ 0xf1,
+ 0xfa,
+ 0x93,
+ 0x98,
+ 0x85,
+ 0x8e,
+ 0xbf,
+ 0xb4,
+ 0xa9,
+ 0xa2,
+ 0xf6,
+ 0xfd,
+ 0xe0,
+ 0xeb,
+ 0xda,
+ 0xd1,
+ 0xcc,
+ 0xc7,
+ 0xae,
+ 0xa5,
+ 0xb8,
+ 0xb3,
+ 0x82,
+ 0x89,
+ 0x94,
+ 0x9f,
+ 0x46,
+ 0x4d,
+ 0x50,
+ 0x5b,
+ 0x6a,
+ 0x61,
+ 0x7c,
+ 0x77,
+ 0x1e,
+ 0x15,
+ 0x08,
+ 0x03,
+ 0x32,
+ 0x39,
+ 0x24,
+ 0x2f,
+ 0x8d,
+ 0x86,
+ 0x9b,
+ 0x90,
+ 0xa1,
+ 0xaa,
+ 0xb7,
+ 0xbc,
+ 0xd5,
+ 0xde,
+ 0xc3,
+ 0xc8,
+ 0xf9,
+ 0xf2,
+ 0xef,
+ 0xe4,
+ 0x3d,
+ 0x36,
+ 0x2b,
+ 0x20,
+ 0x11,
+ 0x1a,
+ 0x07,
+ 0x0c,
+ 0x65,
+ 0x6e,
+ 0x73,
+ 0x78,
+ 0x49,
+ 0x42,
+ 0x5f,
+ 0x54,
+ 0xf7,
+ 0xfc,
+ 0xe1,
+ 0xea,
+ 0xdb,
+ 0xd0,
+ 0xcd,
+ 0xc6,
+ 0xaf,
+ 0xa4,
+ 0xb9,
+ 0xb2,
+ 0x83,
+ 0x88,
+ 0x95,
+ 0x9e,
+ 0x47,
+ 0x4c,
+ 0x51,
+ 0x5a,
+ 0x6b,
+ 0x60,
+ 0x7d,
+ 0x76,
+ 0x1f,
+ 0x14,
+ 0x09,
+ 0x02,
+ 0x33,
+ 0x38,
+ 0x25,
+ 0x2e,
+ 0x8c,
+ 0x87,
+ 0x9a,
+ 0x91,
+ 0xa0,
+ 0xab,
+ 0xb6,
+ 0xbd,
+ 0xd4,
+ 0xdf,
+ 0xc2,
+ 0xc9,
+ 0xf8,
+ 0xf3,
+ 0xee,
+ 0xe5,
+ 0x3c,
+ 0x37,
+ 0x2a,
+ 0x21,
+ 0x10,
+ 0x1b,
+ 0x06,
+ 0x0d,
+ 0x64,
+ 0x6f,
+ 0x72,
+ 0x79,
+ 0x48,
+ 0x43,
+ 0x5e,
+ 0x55,
+ 0x01,
+ 0x0a,
+ 0x17,
+ 0x1c,
+ 0x2d,
+ 0x26,
+ 0x3b,
+ 0x30,
+ 0x59,
+ 0x52,
+ 0x4f,
+ 0x44,
+ 0x75,
+ 0x7e,
+ 0x63,
+ 0x68,
+ 0xb1,
+ 0xba,
+ 0xa7,
+ 0xac,
+ 0x9d,
+ 0x96,
+ 0x8b,
+ 0x80,
+ 0xe9,
+ 0xe2,
+ 0xff,
+ 0xf4,
+ 0xc5,
+ 0xce,
+ 0xd3,
+ 0xd8,
+ 0x7a,
+ 0x71,
+ 0x6c,
+ 0x67,
+ 0x56,
+ 0x5d,
+ 0x40,
+ 0x4b,
+ 0x22,
+ 0x29,
+ 0x34,
+ 0x3f,
+ 0x0e,
+ 0x05,
+ 0x18,
+ 0x13,
+ 0xca,
+ 0xc1,
+ 0xdc,
+ 0xd7,
+ 0xe6,
+ 0xed,
+ 0xf0,
+ 0xfb,
+ 0x92,
+ 0x99,
+ 0x84,
+ 0x8f,
+ 0xbe,
+ 0xb5,
+ 0xa8,
+ 0xa3,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 13 used in
+ * the MixColums step during decryption.
+ */
+ private static final int[] MULT13 = {
+ 0x00,
+ 0x0d,
+ 0x1a,
+ 0x17,
+ 0x34,
+ 0x39,
+ 0x2e,
+ 0x23,
+ 0x68,
+ 0x65,
+ 0x72,
+ 0x7f,
+ 0x5c,
+ 0x51,
+ 0x46,
+ 0x4b,
+ 0xd0,
+ 0xdd,
+ 0xca,
+ 0xc7,
+ 0xe4,
+ 0xe9,
+ 0xfe,
+ 0xf3,
+ 0xb8,
+ 0xb5,
+ 0xa2,
+ 0xaf,
+ 0x8c,
+ 0x81,
+ 0x96,
+ 0x9b,
+ 0xbb,
+ 0xb6,
+ 0xa1,
+ 0xac,
+ 0x8f,
+ 0x82,
+ 0x95,
+ 0x98,
+ 0xd3,
+ 0xde,
+ 0xc9,
+ 0xc4,
+ 0xe7,
+ 0xea,
+ 0xfd,
+ 0xf0,
+ 0x6b,
+ 0x66,
+ 0x71,
+ 0x7c,
+ 0x5f,
+ 0x52,
+ 0x45,
+ 0x48,
+ 0x03,
+ 0x0e,
+ 0x19,
+ 0x14,
+ 0x37,
+ 0x3a,
+ 0x2d,
+ 0x20,
+ 0x6d,
+ 0x60,
+ 0x77,
+ 0x7a,
+ 0x59,
+ 0x54,
+ 0x43,
+ 0x4e,
+ 0x05,
+ 0x08,
+ 0x1f,
+ 0x12,
+ 0x31,
+ 0x3c,
+ 0x2b,
+ 0x26,
+ 0xbd,
+ 0xb0,
+ 0xa7,
+ 0xaa,
+ 0x89,
+ 0x84,
+ 0x93,
+ 0x9e,
+ 0xd5,
+ 0xd8,
+ 0xcf,
+ 0xc2,
+ 0xe1,
+ 0xec,
+ 0xfb,
+ 0xf6,
+ 0xd6,
+ 0xdb,
+ 0xcc,
+ 0xc1,
+ 0xe2,
+ 0xef,
+ 0xf8,
+ 0xf5,
+ 0xbe,
+ 0xb3,
+ 0xa4,
+ 0xa9,
+ 0x8a,
+ 0x87,
+ 0x90,
+ 0x9d,
+ 0x06,
+ 0x0b,
+ 0x1c,
+ 0x11,
+ 0x32,
+ 0x3f,
+ 0x28,
+ 0x25,
+ 0x6e,
+ 0x63,
+ 0x74,
+ 0x79,
+ 0x5a,
+ 0x57,
+ 0x40,
+ 0x4d,
+ 0xda,
+ 0xd7,
+ 0xc0,
+ 0xcd,
+ 0xee,
+ 0xe3,
+ 0xf4,
+ 0xf9,
+ 0xb2,
+ 0xbf,
+ 0xa8,
+ 0xa5,
+ 0x86,
+ 0x8b,
+ 0x9c,
+ 0x91,
+ 0x0a,
+ 0x07,
+ 0x10,
+ 0x1d,
+ 0x3e,
+ 0x33,
+ 0x24,
+ 0x29,
+ 0x62,
+ 0x6f,
+ 0x78,
+ 0x75,
+ 0x56,
+ 0x5b,
+ 0x4c,
+ 0x41,
+ 0x61,
+ 0x6c,
+ 0x7b,
+ 0x76,
+ 0x55,
+ 0x58,
+ 0x4f,
+ 0x42,
+ 0x09,
+ 0x04,
+ 0x13,
+ 0x1e,
+ 0x3d,
+ 0x30,
+ 0x27,
+ 0x2a,
+ 0xb1,
+ 0xbc,
+ 0xab,
+ 0xa6,
+ 0x85,
+ 0x88,
+ 0x9f,
+ 0x92,
+ 0xd9,
+ 0xd4,
+ 0xc3,
+ 0xce,
+ 0xed,
+ 0xe0,
+ 0xf7,
+ 0xfa,
+ 0xb7,
+ 0xba,
+ 0xad,
+ 0xa0,
+ 0x83,
+ 0x8e,
+ 0x99,
+ 0x94,
+ 0xdf,
+ 0xd2,
+ 0xc5,
+ 0xc8,
+ 0xeb,
+ 0xe6,
+ 0xf1,
+ 0xfc,
+ 0x67,
+ 0x6a,
+ 0x7d,
+ 0x70,
+ 0x53,
+ 0x5e,
+ 0x49,
+ 0x44,
+ 0x0f,
+ 0x02,
+ 0x15,
+ 0x18,
+ 0x3b,
+ 0x36,
+ 0x21,
+ 0x2c,
+ 0x0c,
+ 0x01,
+ 0x16,
+ 0x1b,
+ 0x38,
+ 0x35,
+ 0x22,
+ 0x2f,
+ 0x64,
+ 0x69,
+ 0x7e,
+ 0x73,
+ 0x50,
+ 0x5d,
+ 0x4a,
+ 0x47,
+ 0xdc,
+ 0xd1,
+ 0xc6,
+ 0xcb,
+ 0xe8,
+ 0xe5,
+ 0xf2,
+ 0xff,
+ 0xb4,
+ 0xb9,
+ 0xae,
+ 0xa3,
+ 0x80,
+ 0x8d,
+ 0x9a,
+ 0x97,
+ };
+
+ /**
+ * Precalculated lookup table for galois field multiplication by 14 used in
+ * the MixColums step during decryption.
+ */
+ private static final int[] MULT14 = {
+ 0x00,
+ 0x0e,
+ 0x1c,
+ 0x12,
+ 0x38,
+ 0x36,
+ 0x24,
+ 0x2a,
+ 0x70,
+ 0x7e,
+ 0x6c,
+ 0x62,
+ 0x48,
+ 0x46,
+ 0x54,
+ 0x5a,
+ 0xe0,
+ 0xee,
+ 0xfc,
+ 0xf2,
+ 0xd8,
+ 0xd6,
+ 0xc4,
+ 0xca,
+ 0x90,
+ 0x9e,
+ 0x8c,
+ 0x82,
+ 0xa8,
+ 0xa6,
+ 0xb4,
+ 0xba,
+ 0xdb,
+ 0xd5,
+ 0xc7,
+ 0xc9,
+ 0xe3,
+ 0xed,
+ 0xff,
+ 0xf1,
+ 0xab,
+ 0xa5,
+ 0xb7,
+ 0xb9,
+ 0x93,
+ 0x9d,
+ 0x8f,
+ 0x81,
+ 0x3b,
+ 0x35,
+ 0x27,
+ 0x29,
+ 0x03,
+ 0x0d,
+ 0x1f,
+ 0x11,
+ 0x4b,
+ 0x45,
+ 0x57,
+ 0x59,
+ 0x73,
+ 0x7d,
+ 0x6f,
+ 0x61,
+ 0xad,
+ 0xa3,
+ 0xb1,
+ 0xbf,
+ 0x95,
+ 0x9b,
+ 0x89,
+ 0x87,
+ 0xdd,
+ 0xd3,
+ 0xc1,
+ 0xcf,
+ 0xe5,
+ 0xeb,
+ 0xf9,
+ 0xf7,
+ 0x4d,
+ 0x43,
+ 0x51,
+ 0x5f,
+ 0x75,
+ 0x7b,
+ 0x69,
+ 0x67,
+ 0x3d,
+ 0x33,
+ 0x21,
+ 0x2f,
+ 0x05,
+ 0x0b,
+ 0x19,
+ 0x17,
+ 0x76,
+ 0x78,
+ 0x6a,
+ 0x64,
+ 0x4e,
+ 0x40,
+ 0x52,
+ 0x5c,
+ 0x06,
+ 0x08,
+ 0x1a,
+ 0x14,
+ 0x3e,
+ 0x30,
+ 0x22,
+ 0x2c,
+ 0x96,
+ 0x98,
+ 0x8a,
+ 0x84,
+ 0xae,
+ 0xa0,
+ 0xb2,
+ 0xbc,
+ 0xe6,
+ 0xe8,
+ 0xfa,
+ 0xf4,
+ 0xde,
+ 0xd0,
+ 0xc2,
+ 0xcc,
+ 0x41,
+ 0x4f,
+ 0x5d,
+ 0x53,
+ 0x79,
+ 0x77,
+ 0x65,
+ 0x6b,
+ 0x31,
+ 0x3f,
+ 0x2d,
+ 0x23,
+ 0x09,
+ 0x07,
+ 0x15,
+ 0x1b,
+ 0xa1,
+ 0xaf,
+ 0xbd,
+ 0xb3,
+ 0x99,
+ 0x97,
+ 0x85,
+ 0x8b,
+ 0xd1,
+ 0xdf,
+ 0xcd,
+ 0xc3,
+ 0xe9,
+ 0xe7,
+ 0xf5,
+ 0xfb,
+ 0x9a,
+ 0x94,
+ 0x86,
+ 0x88,
+ 0xa2,
+ 0xac,
+ 0xbe,
+ 0xb0,
+ 0xea,
+ 0xe4,
+ 0xf6,
+ 0xf8,
+ 0xd2,
+ 0xdc,
+ 0xce,
+ 0xc0,
+ 0x7a,
+ 0x74,
+ 0x66,
+ 0x68,
+ 0x42,
+ 0x4c,
+ 0x5e,
+ 0x50,
+ 0x0a,
+ 0x04,
+ 0x16,
+ 0x18,
+ 0x32,
+ 0x3c,
+ 0x2e,
+ 0x20,
+ 0xec,
+ 0xe2,
+ 0xf0,
+ 0xfe,
+ 0xd4,
+ 0xda,
+ 0xc8,
+ 0xc6,
+ 0x9c,
+ 0x92,
+ 0x80,
+ 0x8e,
+ 0xa4,
+ 0xaa,
+ 0xb8,
+ 0xb6,
+ 0x0c,
+ 0x02,
+ 0x10,
+ 0x1e,
+ 0x34,
+ 0x3a,
+ 0x28,
+ 0x26,
+ 0x7c,
+ 0x72,
+ 0x60,
+ 0x6e,
+ 0x44,
+ 0x4a,
+ 0x58,
+ 0x56,
+ 0x37,
+ 0x39,
+ 0x2b,
+ 0x25,
+ 0x0f,
+ 0x01,
+ 0x13,
+ 0x1d,
+ 0x47,
+ 0x49,
+ 0x5b,
+ 0x55,
+ 0x7f,
+ 0x71,
+ 0x63,
+ 0x6d,
+ 0xd7,
+ 0xd9,
+ 0xcb,
+ 0xc5,
+ 0xef,
+ 0xe1,
+ 0xf3,
+ 0xfd,
+ 0xa7,
+ 0xa9,
+ 0xbb,
+ 0xb5,
+ 0x9f,
+ 0x91,
+ 0x83,
+ 0x8d,
+ };
+
+ /**
+ * Subroutine of the Rijndael key expansion.
+ */
+ public static BigInteger scheduleCore(BigInteger t, int rconCounter) {
+ StringBuilder rBytes = new StringBuilder(t.toString(16));
+
+ // Add zero padding
+ while (rBytes.length() < 8) {
+ rBytes.insert(0, "0");
+ }
+
+ // rotate the first 16 bits to the back
+ String rotatingBytes = rBytes.substring(0, 2);
+ String fixedBytes = rBytes.substring(2);
+
+ rBytes = new StringBuilder(fixedBytes + rotatingBytes);
+
+ // apply S-Box to all 8-Bit Substrings
+ for (int i = 0; i < 4; i++) {
+ StringBuilder currentByteBits = new StringBuilder(rBytes.substring(i * 2, (i + 1) * 2));
+
+ int currentByte = Integer.parseInt(currentByteBits.toString(), 16);
+ currentByte = SBOX[currentByte];
+
+ // add the current RCON value to the first byte
+ if (i == 0) {
+ currentByte = currentByte ^ RCON[rconCounter];
+ }
+
+ currentByteBits = new StringBuilder(Integer.toHexString(currentByte));
+
+ // Add zero padding
+ while (currentByteBits.length() < 2) {
+ currentByteBits.insert(0, '0');
+ }
+
+ // replace bytes in original string
+ rBytes = new StringBuilder(rBytes.substring(0, i * 2) + currentByteBits + rBytes.substring((i + 1) * 2));
+ }
+
+ return new BigInteger(rBytes.toString(), 16);
+ }
+
+ /**
+ * Returns an array of 10 + 1 round keys that are calculated by using
+ * Rijndael key schedule
+ *
+ * @return array of 10 + 1 round keys
+ */
+ public static BigInteger[] keyExpansion(BigInteger initialKey) {
+ BigInteger[] roundKeys = {
+ initialKey,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ BigInteger.ZERO,
+ };
+
+ // initialize rcon iteration
+ int rconCounter = 1;
+
+ for (int i = 1; i < 11; i++) {
+ // get the previous 32 bits the key
+ BigInteger t = roundKeys[i - 1].remainder(new BigInteger("100000000", 16));
+
+ // split previous key into 8-bit segments
+ BigInteger[] prevKey = {
+ roundKeys[i - 1].remainder(new BigInteger("100000000", 16)),
+ roundKeys[i - 1].remainder(new BigInteger("10000000000000000", 16)).divide(new BigInteger("100000000", 16)),
+ roundKeys[i - 1].remainder(new BigInteger("1000000000000000000000000", 16)).divide(new BigInteger("10000000000000000", 16)),
+ roundKeys[i - 1].divide(new BigInteger("1000000000000000000000000", 16)),
+ };
+
+ // run schedule core
+ t = scheduleCore(t, rconCounter);
+ rconCounter += 1;
+
+ // Calculate partial round key
+ BigInteger t0 = t.xor(prevKey[3]);
+ BigInteger t1 = t0.xor(prevKey[2]);
+ BigInteger t2 = t1.xor(prevKey[1]);
+ BigInteger t3 = t2.xor(prevKey[0]);
+
+ // Join round key segments
+ t2 = t2.multiply(new BigInteger("100000000", 16));
+ t1 = t1.multiply(new BigInteger("10000000000000000", 16));
+ t0 = t0.multiply(new BigInteger("1000000000000000000000000", 16));
+ roundKeys[i] = t0.add(t1).add(t2).add(t3);
+ }
+ return roundKeys;
+ }
+
+ /**
+ * representation of the input 128-bit block as an array of 8-bit integers.
+ *
+ * @param block of 128-bit integers
+ * @return array of 8-bit integers
+ */
+ public static int[] splitBlockIntoCells(BigInteger block) {
+ int[] cells = new int[16];
+ StringBuilder blockBits = new StringBuilder(block.toString(2));
+
+ // Append leading 0 for full "128-bit" string
+ while (blockBits.length() < 128) {
+ blockBits.insert(0, '0');
+ }
+
+ // split 128 to 8 bit cells
+ for (int i = 0; i < cells.length; i++) {
+ String cellBits = blockBits.substring(8 * i, 8 * (i + 1));
+ cells[i] = Integer.parseInt(cellBits, 2);
+ }
+
+ return cells;
+ }
+
+ /**
+ * Returns the 128-bit BigInteger representation of the input of an array of
+ * 8-bit integers.
+ *
+ * @param cells that we need to merge
+ * @return block of merged cells
+ */
+ public static BigInteger mergeCellsIntoBlock(int[] cells) {
+ StringBuilder blockBits = new StringBuilder();
+ for (int i = 0; i < 16; i++) {
+ StringBuilder cellBits = new StringBuilder(Integer.toBinaryString(cells[i]));
+
+ // Append leading 0 for full "8-bit" strings
+ while (cellBits.length() < 8) {
+ cellBits.insert(0, '0');
+ }
+
+ blockBits.append(cellBits);
+ }
+
+ return new BigInteger(blockBits.toString(), 2);
+ }
+
+ /**
+ * @return ciphertext XOR key
+ */
+ public static BigInteger addRoundKey(BigInteger ciphertext, BigInteger key) {
+ return ciphertext.xor(key);
+ }
+
+ /**
+ * substitutes 8-Bit long substrings of the input using the S-Box and
+ * returns the result.
+ *
+ * @return subtraction Output
+ */
+ public static BigInteger subBytes(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+
+ for (int i = 0; i < 16; i++) {
+ cells[i] = SBOX[cells[i]];
+ }
+
+ return mergeCellsIntoBlock(cells);
+ }
+
+ /**
+ * substitutes 8-Bit long substrings of the input using the inverse S-Box
+ * for decryption and returns the result.
+ *
+ * @return subtraction Output
+ */
+ public static BigInteger subBytesDec(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+
+ for (int i = 0; i < 16; i++) {
+ cells[i] = INVERSE_SBOX[cells[i]];
+ }
+
+ return mergeCellsIntoBlock(cells);
+ }
+
+ /**
+ * Cell permutation step. Shifts cells within the rows of the input and
+ * returns the result.
+ */
+ public static BigInteger shiftRows(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+ int[] output = new int[16];
+
+ // do nothing in the first row
+ output[0] = cells[0];
+ output[4] = cells[4];
+ output[8] = cells[8];
+ output[12] = cells[12];
+
+ // shift the second row backwards by one cell
+ output[1] = cells[5];
+ output[5] = cells[9];
+ output[9] = cells[13];
+ output[13] = cells[1];
+
+ // shift the third row backwards by two cell
+ output[2] = cells[10];
+ output[6] = cells[14];
+ output[10] = cells[2];
+ output[14] = cells[6];
+
+ // shift the forth row backwards by tree cell
+ output[3] = cells[15];
+ output[7] = cells[3];
+ output[11] = cells[7];
+ output[15] = cells[11];
+
+ return mergeCellsIntoBlock(output);
+ }
+
+ /**
+ * Cell permutation step for decryption . Shifts cells within the rows of
+ * the input and returns the result.
+ */
+ public static BigInteger shiftRowsDec(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+ int[] output = new int[16];
+
+ // do nothing in the first row
+ output[0] = cells[0];
+ output[4] = cells[4];
+ output[8] = cells[8];
+ output[12] = cells[12];
+
+ // shift the second row forwards by one cell
+ output[1] = cells[13];
+ output[5] = cells[1];
+ output[9] = cells[5];
+ output[13] = cells[9];
+
+ // shift the third row forwards by two cell
+ output[2] = cells[10];
+ output[6] = cells[14];
+ output[10] = cells[2];
+ output[14] = cells[6];
+
+ // shift the forth row forwards by tree cell
+ output[3] = cells[7];
+ output[7] = cells[11];
+ output[11] = cells[15];
+ output[15] = cells[3];
+
+ return mergeCellsIntoBlock(output);
+ }
+
+ /**
+ * Applies the Rijndael MixColumns to the input and returns the result.
+ */
+ public static BigInteger mixColumns(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+ int[] outputCells = new int[16];
+
+ for (int i = 0; i < 4; i++) {
+ int[] row = {
+ cells[i * 4],
+ cells[i * 4 + 1],
+ cells[i * 4 + 2],
+ cells[i * 4 + 3],
+ };
+
+ outputCells[i * 4] = MULT2[row[0]] ^ MULT3[row[1]] ^ row[2] ^ row[3];
+ outputCells[i * 4 + 1] = row[0] ^ MULT2[row[1]] ^ MULT3[row[2]] ^ row[3];
+ outputCells[i * 4 + 2] = row[0] ^ row[1] ^ MULT2[row[2]] ^ MULT3[row[3]];
+ outputCells[i * 4 + 3] = MULT3[row[0]] ^ row[1] ^ row[2] ^ MULT2[row[3]];
+ }
+ return mergeCellsIntoBlock(outputCells);
+ }
+
+ /**
+ * Applies the inverse Rijndael MixColumns for decryption to the input and
+ * returns the result.
+ */
+ public static BigInteger mixColumnsDec(BigInteger ciphertext) {
+ int[] cells = splitBlockIntoCells(ciphertext);
+ int[] outputCells = new int[16];
+
+ for (int i = 0; i < 4; i++) {
+ int[] row = {
+ cells[i * 4],
+ cells[i * 4 + 1],
+ cells[i * 4 + 2],
+ cells[i * 4 + 3],
+ };
+
+ outputCells[i * 4] = MULT14[row[0]] ^ MULT11[row[1]] ^ MULT13[row[2]] ^ MULT9[row[3]];
+ outputCells[i * 4 + 1] = MULT9[row[0]] ^ MULT14[row[1]] ^ MULT11[row[2]] ^ MULT13[row[3]];
+ outputCells[i * 4 + 2] = MULT13[row[0]] ^ MULT9[row[1]] ^ MULT14[row[2]] ^ MULT11[row[3]];
+ outputCells[i * 4 + 3] = MULT11[row[0]] ^ MULT13[row[1]] ^ MULT9[row[2]] ^ MULT14[row[3]];
+ }
+ return mergeCellsIntoBlock(outputCells);
+ }
+
+ /**
+ * Encrypts the plaintext with the key and returns the result
+ *
+ * @param plainText which we want to encrypt
+ * @param key the key for encrypt
+ * @return EncryptedText
+ */
+ public static BigInteger encrypt(BigInteger plainText, BigInteger key) {
+ BigInteger[] roundKeys = keyExpansion(key);
+
+ // Initial round
+ plainText = addRoundKey(plainText, roundKeys[0]);
+
+ // Main rounds
+ for (int i = 1; i < 10; i++) {
+ plainText = subBytes(plainText);
+ plainText = shiftRows(plainText);
+ plainText = mixColumns(plainText);
+ plainText = addRoundKey(plainText, roundKeys[i]);
+ }
+
+ // Final round
+ plainText = subBytes(plainText);
+ plainText = shiftRows(plainText);
+ plainText = addRoundKey(plainText, roundKeys[10]);
+
+ return plainText;
+ }
+
+ /**
+ * Decrypts the ciphertext with the key and returns the result
+ *
+ * @param cipherText The Encrypted text which we want to decrypt
+ * @return decryptedText
+ */
+ public static BigInteger decrypt(BigInteger cipherText, BigInteger key) {
+ BigInteger[] roundKeys = keyExpansion(key);
+
+ // Invert final round
+ cipherText = addRoundKey(cipherText, roundKeys[10]);
+ cipherText = shiftRowsDec(cipherText);
+ cipherText = subBytesDec(cipherText);
+
+ // Invert main rounds
+ for (int i = 9; i > 0; i--) {
+ cipherText = addRoundKey(cipherText, roundKeys[i]);
+ cipherText = mixColumnsDec(cipherText);
+ cipherText = shiftRowsDec(cipherText);
+ cipherText = subBytesDec(cipherText);
+ }
+
+ // Invert initial round
+ cipherText = addRoundKey(cipherText, roundKeys[0]);
+
+ return cipherText;
+ }
+
+ public static void main(String[] args) {
+ try (Scanner input = new Scanner(System.in)) {
+ System.out.println("Enter (e) letter for encrypt or (d) letter for decrypt :");
+ char choice = input.nextLine().charAt(0);
+ String in;
+ switch (choice) {
+ case 'E', 'e' -> {
+ System.out.println(
+ "Choose a plaintext block (128-Bit Integer in base 16):"
+ );
+ in = input.nextLine();
+ BigInteger plaintext = new BigInteger(in, 16);
+ System.out.println(
+ "Choose a Key (128-Bit Integer in base 16):"
+ );
+ in = input.nextLine();
+ BigInteger encryptionKey = new BigInteger(in, 16);
+ System.out.println(
+ "The encrypted message is: \n"
+ + encrypt(plaintext, encryptionKey).toString(16)
+ );
+ }
+ case 'D', 'd' -> {
+ System.out.println(
+ "Enter your ciphertext block (128-Bit Integer in base 16):"
+ );
+ in = input.nextLine();
+ BigInteger ciphertext = new BigInteger(in, 16);
+ System.out.println(
+ "Choose a Key (128-Bit Integer in base 16):"
+ );
+ in = input.nextLine();
+ BigInteger decryptionKey = new BigInteger(in, 16);
+ System.out.println(
+ "The deciphered message is:\n"
+ + decrypt(ciphertext, decryptionKey).toString(16)
+ );
+ }
+ default -> System.out.println("** End **");
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AESEncryption.java b/src/main/java/com/thealgorithms/ciphers/AESEncryption.java
new file mode 100644
index 000000000000..14582205442f
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AESEncryption.java
@@ -0,0 +1,104 @@
+package com.thealgorithms.ciphers;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * This example program shows how AES encryption and decryption can be done in
+ * Java. Please note that secret key and encrypted text is unreadable binary and
+ * hence in the following program we display it in hexadecimal format of the
+ * underlying bytes.
+ */
+public final class AESEncryption {
+ private AESEncryption() {
+ }
+
+ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+ private static Cipher aesCipher;
+
+ /**
+ * 1. Generate a plain text for encryption 2. Get a secret key (printed in
+ * hexadecimal form). In actual use this must be encrypted and kept safe.
+ * The same key is required for decryption.
+ */
+ public static void main(String[] args) throws Exception {
+ String plainText = "Hello World";
+ SecretKey secKey = getSecretEncryptionKey();
+ byte[] cipherText = encryptText(plainText, secKey);
+ String decryptedText = decryptText(cipherText, secKey);
+
+ System.out.println("Original Text:" + plainText);
+ System.out.println("AES Key (Hex Form):" + bytesToHex(secKey.getEncoded()));
+ System.out.println("Encrypted Text (Hex Form):" + bytesToHex(cipherText));
+ System.out.println("Descrypted Text:" + decryptedText);
+ }
+
+ /**
+ * gets the AES encryption key. In your actual programs, this should be
+ * safely stored.
+ *
+ * @return secKey (Secret key that we encrypt using it)
+ * @throws NoSuchAlgorithmException (from KeyGenrator)
+ */
+ public static SecretKey getSecretEncryptionKey() throws NoSuchAlgorithmException {
+ KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
+ aesKeyGenerator.init(128); // The AES key size in number of bits
+ return aesKeyGenerator.generateKey();
+ }
+
+ /**
+ * Encrypts plainText in AES using the secret key
+ *
+ * @return byteCipherText (The encrypted text)
+ * @throws NoSuchPaddingException (from Cipher)
+ * @throws NoSuchAlgorithmException (from Cipher)
+ * @throws InvalidKeyException (from Cipher)
+ * @throws BadPaddingException (from Cipher)
+ * @throws IllegalBlockSizeException (from Cipher)
+ */
+ public static byte[] encryptText(String plainText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
+ // AES defaults to AES/ECB/PKCS5Padding in Java 7
+ aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
+ aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
+ return aesCipher.doFinal(plainText.getBytes());
+ }
+
+ /**
+ * Decrypts encrypted byte array using the key used for encryption.
+ *
+ * @return plainText
+ */
+ public static String decryptText(byte[] byteCipherText, SecretKey secKey) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException {
+ // AES defaults to AES/ECB/PKCS5Padding in Java 7
+ Cipher decryptionCipher = Cipher.getInstance("AES/GCM/NoPadding");
+ GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, aesCipher.getIV());
+ decryptionCipher.init(Cipher.DECRYPT_MODE, secKey, gcmParameterSpec);
+ byte[] bytePlainText = decryptionCipher.doFinal(byteCipherText);
+ return new String(bytePlainText);
+ }
+
+ /**
+ * Convert a binary byte array into readable hex form Old library is
+ * deprecated on OpenJdk 11 and this is faster regarding other solution is
+ * using StringBuilder
+ *
+ * @return hexHash
+ */
+ public static String bytesToHex(byte[] bytes) {
+ char[] hexChars = new char[bytes.length * 2];
+ for (int j = 0; j < bytes.length; j++) {
+ int v = bytes[j] & 0xFF;
+ hexChars[j * 2] = HEX_ARRAY[v >>> 4];
+ hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
+ }
+ return new String(hexChars);
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AffineCipher.java b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java
new file mode 100644
index 000000000000..979f18532eaa
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AffineCipher.java
@@ -0,0 +1,87 @@
+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() {
+ }
+
+ // Key values of a and b
+ 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
+ StringBuilder cipher = new StringBuilder();
+ for (int i = 0; i < msg.length; i++) {
+ // Avoid space to be encrypted
+ /* applying encryption formula ( a * x + b ) mod m
+ {here x is msg[i] and m is 26} and added 'A' to
+ bring it in the range of ASCII alphabet [65-90 | A-Z] */
+ if (msg[i] != ' ') {
+ cipher.append((char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A'));
+ } else { // else simply append space character
+ cipher.append(msg[i]);
+ }
+ }
+ return cipher.toString();
+ }
+
+ /**
+ * Decrypts a ciphertext using the Affine cipher.
+ *
+ * @param cipher the ciphertext to decrypt
+ * @return the decrypted plaintext message
+ */
+ static String decryptCipher(String cipher) {
+ StringBuilder msg = new StringBuilder();
+ int aInv = 0;
+ int flag;
+
+ // 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,
+ // then i will be the multiplicative inverse of a
+ if (flag == 1) {
+ aInv = i;
+ break;
+ }
+ }
+ for (int i = 0; i < cipher.length(); i++) {
+ /* 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 the range of ASCII alphabet [65-90 | A-Z] */
+ if (cipher.charAt(i) != ' ') {
+ msg.append((char) (((aInv * ((cipher.charAt(i) - 'A') - b + 26)) % 26) + 'A'));
+ } else { // else simply append space character
+ msg.append(cipher.charAt(i));
+ }
+ }
+
+ return msg.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
new file mode 100644
index 000000000000..9169aa82bd75
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/AtbashCipher.java
@@ -0,0 +1,101 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * The Atbash cipher is a classic substitution cipher that substitutes each letter
+ * with its opposite letter in the alphabet.
+ *
+ * For example:
+ * - 'A' becomes 'Z', 'B' becomes 'Y', 'C' becomes 'X', and so on.
+ * - Similarly, 'a' becomes 'z', 'b' becomes 'y', and so on.
+ *
+ * The cipher works identically for both uppercase and lowercase letters.
+ * Non-alphabetical characters remain unchanged in the output.
+ *
+ * This cipher is symmetric, meaning that applying the cipher twice will return
+ * the original text. Therefore, the same function is used for both encryption and decryption.
+ *
+ * Usage Example:
+ *
+ * AtbashCipher cipher = new AtbashCipher("Hello World!");
+ * String encrypted = cipher.convert(); // Output: "Svool Dliow!"
+ *
+ *
+ * @author Krounosity
+ * @see Atbash Cipher (Wikipedia)
+ */
+public class AtbashCipher {
+
+ private String toConvert;
+
+ public AtbashCipher() {
+ }
+
+ /**
+ * Constructor with a string parameter.
+ *
+ * @param str The string to be converted using the Atbash cipher
+ */
+ public AtbashCipher(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Returns the current string set for conversion.
+ *
+ * @return The string to be converted
+ */
+ public String getString() {
+ return toConvert;
+ }
+
+ /**
+ * Sets the string to be converted using the Atbash cipher.
+ *
+ * @param str The new string to convert
+ */
+ public void setString(String str) {
+ this.toConvert = str;
+ }
+
+ /**
+ * Checks if a character is uppercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is uppercase, {@code false} otherwise
+ */
+ private boolean isCapital(char ch) {
+ return ch >= 'A' && ch <= 'Z';
+ }
+
+ /**
+ * Checks if a character is lowercase.
+ *
+ * @param ch The character to check
+ * @return {@code true} if the character is lowercase, {@code false} otherwise
+ */
+ private boolean isSmall(char ch) {
+ return ch >= 'a' && ch <= 'z';
+ }
+
+ /**
+ * Converts the input string using the Atbash cipher.
+ * Alphabetic characters are substituted with their opposite in the alphabet,
+ * while non-alphabetic characters remain unchanged.
+ *
+ * @return The converted string after applying the Atbash cipher
+ */
+ public String convert() {
+ StringBuilder convertedString = new StringBuilder();
+
+ for (char ch : toConvert.toCharArray()) {
+ if (isSmall(ch)) {
+ convertedString.append((char) ('z' - (ch - 'a')));
+ } else if (isCapital(ch)) {
+ convertedString.append((char) ('Z' - (ch - 'A')));
+ } else {
+ convertedString.append(ch);
+ }
+ }
+ return convertedString.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/Autokey.java b/src/main/java/com/thealgorithms/ciphers/Autokey.java
new file mode 100644
index 000000000000..bb67f512accf
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/Autokey.java
@@ -0,0 +1,55 @@
+package com.thealgorithms.ciphers;
+
+/**
+ * The Autokey Cipher is an interesting and historically significant encryption method,
+ * as it improves upon the classic Vigenère Cipher by using the plaintext itself to
+ * extend the key. This makes it harder to break using frequency analysis, as it
+ * doesn’t rely solely on a repeated key.
+ * https://en.wikipedia.org/wiki/Autokey_cipher
+ *
+ * @author bennybebo
+ */
+public class Autokey {
+
+ // Encrypts the plaintext using the Autokey cipher
+ public String encrypt(String plaintext, String keyword) {
+ plaintext = plaintext.toUpperCase().replaceAll("[^A-Z]", ""); // Sanitize input
+ keyword = keyword.toUpperCase();
+
+ StringBuilder extendedKey = new StringBuilder(keyword);
+ extendedKey.append(plaintext); // Extend key with plaintext
+
+ StringBuilder ciphertext = new StringBuilder();
+
+ for (int i = 0; i < plaintext.length(); i++) {
+ char plainChar = plaintext.charAt(i);
+ char keyChar = extendedKey.charAt(i);
+
+ int encryptedChar = (plainChar - 'A' + keyChar - 'A') % 26 + 'A';
+ ciphertext.append((char) encryptedChar);
+ }
+
+ return ciphertext.toString();
+ }
+
+ // Decrypts the ciphertext using the Autokey cipher
+ public String decrypt(String ciphertext, String keyword) {
+ ciphertext = ciphertext.toUpperCase().replaceAll("[^A-Z]", ""); // Sanitize input
+ keyword = keyword.toUpperCase();
+
+ StringBuilder plaintext = new StringBuilder();
+ StringBuilder extendedKey = new StringBuilder(keyword);
+
+ for (int i = 0; i < ciphertext.length(); i++) {
+ char cipherChar = ciphertext.charAt(i);
+ char keyChar = extendedKey.charAt(i);
+
+ int decryptedChar = (cipherChar - 'A' - (keyChar - 'A') + 26) % 26 + 'A';
+ plaintext.append((char) decryptedChar);
+
+ extendedKey.append((char) decryptedChar); // Extend key with each decrypted char
+ }
+
+ return plaintext.toString();
+ }
+}
diff --git a/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java b/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java
new file mode 100644
index 000000000000..16dfd6e674af
--- /dev/null
+++ b/src/main/java/com/thealgorithms/ciphers/BaconianCipher.java
@@ -0,0 +1,71 @@
+package com.thealgorithms.ciphers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The Baconian Cipher is a substitution cipher where each letter is represented
+ * by a group of five binary digits (A's and B's). It can also be used to hide
+ * messages within other texts, making it a simple form of steganography.
+ * https://en.wikipedia.org/wiki/Bacon%27s_cipher
+ *
+ * @author Bennybebo
+ */
+public class BaconianCipher {
+
+ private static final Map BACONIAN_MAP = new HashMap<>();
+ private static final Map