Date: Tue, 26 Oct 2021 13:47:15 +0800
Subject: [PATCH 0057/1552] Add LRU Cache (#2740)
---
DIRECTORY.md | 19 ++-
DataStructures/Caches/LRUCache.java | 182 ++++++++++++++++++++++++++++
2 files changed, 200 insertions(+), 1 deletion(-)
create mode 100644 DataStructures/Caches/LRUCache.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index e8be02fd21e0..4fd29a368cf4 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -1,5 +1,5 @@
-## Audio Filters
+## AudioFilters
* [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/AudioFilters/IIRFilter.java)
## Backtracking
@@ -46,11 +46,17 @@
* [Bag](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Bags/Bag.java)
* Buffers
* [CircularBuffer](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Buffers/CircularBuffer.java)
+ * Caches
+ * [LRUCache](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Caches/LRUCache.java)
+ * DisjointSets
+ * [DisjointSets](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/DisjointSets.java)
+ * [Node](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/Node.java)
* DynamicArray
* [DynamicArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DynamicArray/DynamicArray.java)
* Graphs
* [A Star](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/A_Star.java)
* [BellmanFord](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/BellmanFord.java)
+ * [BipartiteGrapfDFS](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/BipartiteGrapfDFS.java)
* [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/ConnectedComponent.java)
* [Cycles](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/Cycles.java)
* [DIJSKSTRAS ALGORITHM](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Graphs/DIJSKSTRAS_ALGORITHM.java)
@@ -96,6 +102,7 @@
* [InfixToPostfix](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/InfixToPostfix.java)
* [MaximumMinimumWindow](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/MaximumMinimumWindow.java)
* [NodeStack](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/NodeStack.java)
+ * [ReverseStack](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/ReverseStack.java)
* [StackArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackArray.java)
* [StackArrayList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackArrayList.java)
* [StackOfLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Stacks/StackOfLinkedList.java)
@@ -113,6 +120,7 @@
* [LevelOrderTraversalQueue](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversalQueue.java)
* [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/PrintTopViewofTree.java)
* [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/RedBlackBST.java)
+ * [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/SegmentTree.java)
* [TreeTraversal](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/TreeTraversal.java)
* [TrieImp](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/TrieImp.java)
* [ValidBSTOrNot](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/ValidBSTOrNot.java)
@@ -145,6 +153,7 @@
* [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/LongestPalindromicSubstring.java)
* [LongestValidParentheses](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/LongestValidParentheses.java)
* [MatrixChainMultiplication](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MatrixChainMultiplication.java)
+ * [MatrixChainRecursiveTopDownMemoisation](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MatrixChainRecursiveTopDownMemoisation.java)
* [MemoizationTechniqueKnapsack](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MemoizationTechniqueKnapsack.java)
* [MinimumPathSum](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MinimumPathSum.java)
* [MinimumSumPartition](https://github.com/TheAlgorithms/Java/blob/master/DynamicProgramming/MinimumSumPartition.java)
@@ -181,6 +190,7 @@
* [FactorialRecursion](https://github.com/TheAlgorithms/Java/blob/master/Maths/FactorialRecursion.java)
* [FFT](https://github.com/TheAlgorithms/Java/blob/master/Maths/FFT.java)
* [FFTBluestein](https://github.com/TheAlgorithms/Java/blob/master/Maths/FFTBluestein.java)
+ * [FibonacciJavaStreams](https://github.com/TheAlgorithms/Java/blob/master/Maths/FibonacciJavaStreams.java)
* [FibonacciNumber](https://github.com/TheAlgorithms/Java/blob/master/Maths/FibonacciNumber.java)
* [FindMax](https://github.com/TheAlgorithms/Java/blob/master/Maths/FindMax.java)
* [FindMaxRecursion](https://github.com/TheAlgorithms/Java/blob/master/Maths/FindMaxRecursion.java)
@@ -216,8 +226,10 @@
* [PrimeFactorization](https://github.com/TheAlgorithms/Java/blob/master/Maths/PrimeFactorization.java)
* [PythagoreanTriple](https://github.com/TheAlgorithms/Java/blob/master/Maths/PythagoreanTriple.java)
* [RomanNumeralUtil](https://github.com/TheAlgorithms/Java/blob/master/Maths/RomanNumeralUtil.java)
+ * [SimpsonIntegration](https://github.com/TheAlgorithms/Java/blob/master/Maths/SimpsonIntegration.java)
* [SumOfArithmeticSeries](https://github.com/TheAlgorithms/Java/blob/master/Maths/SumOfArithmeticSeries.java)
* [SumOfDigits](https://github.com/TheAlgorithms/Java/blob/master/Maths/SumOfDigits.java)
+ * [TrinomialTriangle](https://github.com/TheAlgorithms/Java/blob/master/Maths/TrinomialTriangle.java)
* [VampireNumber](https://github.com/TheAlgorithms/Java/blob/master/Maths/VampireNumber.java)
* [VectorCrossProduct](https://github.com/TheAlgorithms/Java/blob/master/Maths/VectorCrossProduct.java)
@@ -234,6 +246,7 @@
* [MedianOfRunningArray](https://github.com/TheAlgorithms/Java/blob/master/Misc/MedianOfRunningArray.java)
* [PalindromePrime](https://github.com/TheAlgorithms/Java/blob/master/Misc/PalindromePrime.java)
* [RangeInSortedArray](https://github.com/TheAlgorithms/Java/blob/master/Misc/RangeInSortedArray.java)
+ * [Sparcity](https://github.com/TheAlgorithms/Java/blob/master/Misc/Sparcity.java)
* [TwoSumProblem](https://github.com/TheAlgorithms/Java/blob/master/Misc/TwoSumProblem.java)
* [WordBoggle](https://github.com/TheAlgorithms/Java/blob/master/Misc/WordBoggle.java)
@@ -289,6 +302,7 @@
## Searches
* [BinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/BinarySearch.java)
* [ExponentalSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/ExponentalSearch.java)
+ * [FibonacciSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/FibonacciSearch.java)
* [HowManyTimesRotated](https://github.com/TheAlgorithms/Java/blob/master/Searches/HowManyTimesRotated.java)
* [InterpolationSearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/InterpolationSearch.java)
* [IterativeBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/IterativeBinarySearch.java)
@@ -310,6 +324,7 @@
* [BubbleSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BubbleSort.java)
* [BubbleSortRecursion](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BubbleSortRecursion.java)
* [BucketSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BucketSort.java)
+ * [CircleSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CircleSort.java)
* [CocktailShakerSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CocktailShakerSort.java)
* [CombSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CombSort.java)
* [CountingSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/CountingSort.java)
@@ -319,6 +334,7 @@
* [HeapSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/HeapSort.java)
* [InsertionSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/InsertionSort.java)
* [MergeSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSort.java)
+ * [MergeSortNoExtraSpace](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSortNoExtraSpace.java)
* [MergeSortRecursive](https://github.com/TheAlgorithms/Java/blob/master/Sorts/MergeSortRecursive.java)
* [PancakeSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/PancakeSort.java)
* [QuickSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/QuickSort.java)
@@ -345,6 +361,7 @@
* [Lower](https://github.com/TheAlgorithms/Java/blob/master/Strings/Lower.java)
* [Palindrome](https://github.com/TheAlgorithms/Java/blob/master/Strings/Palindrome.java)
* [Pangram](https://github.com/TheAlgorithms/Java/blob/master/Strings/Pangram.java)
+ * [PermuteString](https://github.com/TheAlgorithms/Java/blob/master/Strings/PermuteString.java)
* [ReverseString](https://github.com/TheAlgorithms/Java/blob/master/Strings/ReverseString.java)
* [Rotation](https://github.com/TheAlgorithms/Java/blob/master/Strings/Rotation.java)
* [Upper](https://github.com/TheAlgorithms/Java/blob/master/Strings/Upper.java)
diff --git a/DataStructures/Caches/LRUCache.java b/DataStructures/Caches/LRUCache.java
new file mode 100644
index 000000000000..033aad60099b
--- /dev/null
+++ b/DataStructures/Caches/LRUCache.java
@@ -0,0 +1,182 @@
+package DataStructures.Caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Least recently used (LRU)
+ *
+ * Discards the least recently used items first.
+ * This algorithm requires keeping track of what was used when,
+ * which is expensive if one wants to make sure the algorithm always discards
+ * the least recently used item.
+ * https://en.wikipedia.org/wiki/Cache_replacement_policies#Least_recently_used_(LRU)
+ *
+ * @param key type
+ * @param value type
+ */
+public class LRUCache {
+ private final Map> data = new HashMap<>();
+ private Entry head;
+ private Entry tail;
+ private int cap;
+ private static final int DEFAULT_CAP = 100;
+
+ public LRUCache() {
+ setCapacity(DEFAULT_CAP);
+ }
+
+ public LRUCache(int cap) {
+ setCapacity(cap);
+ }
+
+ private void setCapacity(int newCapacity) {
+ checkCapacity(newCapacity);
+ for (int i = data.size(); i > newCapacity; i--) {
+ Entry evicted = evict();
+ data.remove(evicted.getKey());
+ }
+ this.cap = newCapacity;
+ }
+
+ private Entry evict() {
+ if (head == null) {
+ throw new RuntimeException("cache cannot be empty!");
+ }
+ Entry evicted = head;
+ head = evicted.getNextEntry();
+ head.setPreEntry(null);
+ evicted.setNextEntry(null);
+ return evicted;
+ }
+
+ private void checkCapacity(int capacity) {
+ if (capacity <= 0) {
+ throw new RuntimeException("capacity must greater than 0!");
+ }
+ }
+
+ public V get(K key) {
+ if (!data.containsKey(key)) {
+ return null;
+ }
+ final Entry entry = data.get(key);
+ moveNodeToLast(entry);
+ return entry.getValue();
+ }
+
+ private void moveNodeToLast(Entry entry) {
+ if (tail == entry) {
+ return;
+ }
+ final Entry preEntry = entry.getPreEntry();
+ final Entry nextEntry = entry.getNextEntry();
+ if (preEntry != null) {
+ preEntry.setNextEntry(nextEntry);
+ }
+ if (nextEntry != null) {
+ nextEntry.setPreEntry(preEntry);
+ }
+ if (head == entry) {
+ head = nextEntry;
+ }
+ tail.setNextEntry(entry);
+ entry.setPreEntry(tail);
+ entry.setNextEntry(null);
+ tail = entry;
+ }
+
+ public void put(K key, V value) {
+ if (data.containsKey(key)) {
+ final Entry existingEntry = data.get(key);
+ existingEntry.setValue(value);
+ moveNodeToLast(existingEntry);
+ return;
+ }
+ Entry newEntry;
+ if (data.size() == cap) {
+ newEntry = evict();
+ data.remove(newEntry.getKey());
+ } else {
+ newEntry = new Entry<>();
+ }
+
+ newEntry.setKey(key);
+ newEntry.setValue(value);
+ addNewEntry(newEntry);
+ data.put(key, newEntry);
+ }
+
+ private void addNewEntry(Entry newEntry) {
+ if (data.isEmpty()) {
+ head = newEntry;
+ tail = newEntry;
+ return;
+ }
+ tail.setNextEntry(newEntry);
+ newEntry.setPreEntry(tail);
+ newEntry.setNextEntry(null);
+ tail = newEntry;
+ }
+
+ static final class Entry {
+ private Entry preEntry;
+ private Entry nextEntry;
+ private I key;
+ private J value;
+
+ public Entry() {
+ }
+
+ public Entry(Entry preEntry, Entry nextEntry, I key, J value) {
+ this.preEntry = preEntry;
+ this.nextEntry = nextEntry;
+ this.key = key;
+ this.value = value;
+ }
+
+ public Entry getPreEntry() {
+ return preEntry;
+ }
+
+ public void setPreEntry(Entry preEntry) {
+ this.preEntry = preEntry;
+ }
+
+ public Entry getNextEntry() {
+ return nextEntry;
+ }
+
+ public void setNextEntry(Entry nextEntry) {
+ this.nextEntry = nextEntry;
+ }
+
+ public I getKey() {
+ return key;
+ }
+
+ public void setKey(I key) {
+ this.key = key;
+ }
+
+ public J getValue() {
+ return value;
+ }
+
+ public void setValue(J value) {
+ this.value = value;
+ }
+ }
+
+ public static void main(String[] args) {
+ final LRUCache cache = new LRUCache<>(2);
+ cache.put("Key1", 1);
+ cache.put("Key2", 2);
+ cache.put("Key3", 3);
+ cache.put("Key4", 4);
+ System.out.println("getValue(Key1): " + cache.get("Key1"));
+ System.out.println("getValue(Key2): " + cache.get("Key2"));
+ System.out.println("getValue(Key3): " + cache.get("Key3"));
+ System.out.println("getValue(Key4): " + cache.get("Key4"));
+ }
+}
From ec127df959125d16c2d815fedf327919845eb359 Mon Sep 17 00:00:00 2001
From: Limbad Yash <56826569+limbad-YK@users.noreply.github.com>
Date: Tue, 26 Oct 2021 11:34:28 +0530
Subject: [PATCH 0058/1552] Add Knight's Tour (#2701)
---
Backtracking/KnightsTour.java | 126 ++++++++++++++++++++++++++++++++++
1 file changed, 126 insertions(+)
create mode 100644 Backtracking/KnightsTour.java
diff --git a/Backtracking/KnightsTour.java b/Backtracking/KnightsTour.java
new file mode 100644
index 000000000000..d6e454b68ebd
--- /dev/null
+++ b/Backtracking/KnightsTour.java
@@ -0,0 +1,126 @@
+package Backtracking;
+
+import java.util.*;
+
+/*
+ * Problem Statement: -
+
+ Given a N*N board with the Knight placed on the first block of an empty board. Moving according to the rules of
+ chess knight must visit each square exactly once. Print the order of each cell in which they are visited.
+
+ Example: -
+
+ Input : N = 8
+
+ Output:
+ 0 59 38 33 30 17 8 63
+ 37 34 31 60 9 62 29 16
+ 58 1 36 39 32 27 18 7
+ 35 48 41 26 61 10 15 28
+ 42 57 2 49 40 23 6 19
+ 47 50 45 54 25 20 11 14
+ 56 43 52 3 22 13 24 5
+ 51 46 55 44 53 4 21 12
+
+ */
+
+public class KnightsTour {
+ private final static int base = 12;
+ private final static int[][] moves = {{1,-2},{2,-1},{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2}}; // Possible moves by knight on chess
+ private static int[][] grid; // chess grid
+ private static int total; // total squares in chess
+
+ public static void main(String[] args) {
+ 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;
+
+ int row = 2 + (int) (Math.random() * (base - 4));
+ int col = 2 + (int) (Math.random() * (base - 4));
+
+ grid[row][col] = 1;
+
+ if (solve(row, col, 2))
+ printResult();
+ else System.out.println("no result");
+
+ }
+
+ // Return True when solvable
+ private 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;
+
+ Collections.sort(neighbor, new Comparator() {
+ public int compare(int[] a, int[] b) {
+ return a[2] - b[2];
+ }
+ });
+
+ for (int[] nb : neighbor) {
+ row = nb[0];
+ column = nb[1];
+ grid[row][column] = count;
+ if (!orphanDetected(count, row, column) && solve(row, column, count + 1))
+ return true;
+ grid[row][column] = 0;
+ }
+
+ return false;
+ }
+
+ // Returns List of neighbours
+ private static List neighbors(int row, int column) {
+ List neighbour = new ArrayList<>();
+
+ for (int[] m : moves) {
+ int x = m[0];
+ int y = m[1];
+ if (grid[row + y][column + x] == 0) {
+ int num = countNeighbors(row + y, column + x);
+ neighbour.add(new int[]{row + y, column + x, num});
+ }
+ }
+ return neighbour;
+ }
+
+ // Returns the total count of neighbors
+ private static int countNeighbors(int row, int column) {
+ int num = 0;
+ for (int[] m : moves)
+ if (grid[row + m[1]][column + m[0]] == 0)
+ num++;
+ return num;
+ }
+
+ // Returns true if it is orphan
+ private 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;
+ }
+
+ // Prints the result grid
+ private static void printResult() {
+ for (int[] row : grid) {
+ for (int i : row) {
+ if (i == -1) continue;
+ System.out.printf("%2d ", i);
+ }
+ System.out.println();
+ }
+ }
+}
From b02a3fc818262db97b0ede1aa8e7847abf606236 Mon Sep 17 00:00:00 2001
From: Amit Kumar
Date: Tue, 26 Oct 2021 11:42:50 +0530
Subject: [PATCH 0059/1552] Create a binary tree from inorder and preorder
traversal given in array form (Fixes: #2707) (#2710)
Co-authored-by: Amit Kumar
---
DataStructures/Trees/BinaryTree.java | 7 +-
.../CreateBinaryTreeFromInorderPreorder.java | 95 +++++++++++++++++++
2 files changed, 101 insertions(+), 1 deletion(-)
create mode 100644 DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java
diff --git a/DataStructures/Trees/BinaryTree.java b/DataStructures/Trees/BinaryTree.java
index a9003d4bb322..0669f80fd8c3 100644
--- a/DataStructures/Trees/BinaryTree.java
+++ b/DataStructures/Trees/BinaryTree.java
@@ -22,7 +22,7 @@ public class BinaryTree {
*
* @author Unknown
*/
- class Node {
+ static class Node {
/** Data for the node */
public int data;
/** The Node to the left of this one */
@@ -53,6 +53,11 @@ public BinaryTree() {
root = null;
}
+ /** Parameterized Constructor */
+ public BinaryTree(Node root) {
+ this.root = root;
+ }
+
/**
* Method to find a Node with a certain value
*
diff --git a/DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java b/DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java
new file mode 100644
index 000000000000..ea9583bb3f94
--- /dev/null
+++ b/DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java
@@ -0,0 +1,95 @@
+package DataStructures.Trees;
+
+import java.util.HashMap;
+import java.util.Map;
+import DataStructures.Trees.BinaryTree.Node;
+
+/**
+ * Approach: Naive Solution: Create root node from first value present in
+ * preorder traversal. Look for the index of root node's value in inorder
+ * traversal. That will tell total nodes present in left subtree and right
+ * subtree. Based on that index create left and right subtree.
+ * Complexity:
+ * Time: O(n^2) for each node there is iteration to find index in inorder array
+ * Space: Stack size = O(height) = O(lg(n))
+ *
+ * Optimized Solution: Instead of iterating over inorder array to find index of
+ * root value, create a hashmap and find out the index of root value.
+ * Complexity:
+ * Time: O(n) hashmap reduced iteration to find index in inorder array
+ * Space: O(n) space taken by hashmap
+ *
+ */
+public class CreateBinaryTreeFromInorderPreorder {
+ public static void main(String[] args) {
+ test(new Integer[] {}, new Integer[] {}); // empty tree
+ test(new Integer[] { 1 }, new Integer[] { 1 }); // single node tree
+ test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 1, 2, 3, 4 }); // right skewed tree
+ test(new Integer[] { 1, 2, 3, 4 }, new Integer[] { 4, 3, 2, 1 }); // left skewed tree
+ test(new Integer[] { 3, 9, 20, 15, 7 }, new Integer[] { 9, 3, 15, 20, 7 }); // normal tree
+ }
+
+ private static void test(final Integer[] preorder, final Integer[] inorder) {
+ System.out.println("\n====================================================");
+ System.out.println("Naive Solution...");
+ BinaryTree root = new BinaryTree(createTree(preorder, inorder, 0, 0, inorder.length));
+ System.out.println("Preorder Traversal: ");
+ root.preOrder(root.getRoot());
+ System.out.println("\nInorder Traversal: ");
+ root.inOrder(root.getRoot());
+ System.out.println("\nPostOrder Traversal: ");
+ root.postOrder(root.getRoot());
+
+ Map map = new HashMap<>();
+ for (int i = 0; i < inorder.length; i++) {
+ map.put(inorder[i], i);
+ }
+ BinaryTree optimizedRoot = new BinaryTree(createTreeOptimized(preorder, inorder, 0, 0, inorder.length, map));
+ System.out.println("\n\nOptimized solution...");
+ System.out.println("Preorder Traversal: ");
+ optimizedRoot.preOrder(root.getRoot());
+ System.out.println("\nInorder Traversal: ");
+ optimizedRoot.inOrder(root.getRoot());
+ System.out.println("\nPostOrder Traversal: ");
+ optimizedRoot.postOrder(root.getRoot());
+ }
+
+ private static Node createTree(final Integer[] preorder, final Integer[] inorder,
+ final int preStart, final int inStart, final int size) {
+ if (size == 0) {
+ return null;
+ }
+
+ Node root = new Node(preorder[preStart]);
+ int i = inStart;
+ while (preorder[preStart] != inorder[i]) {
+ i++;
+ }
+ int leftNodesCount = i - inStart;
+ int rightNodesCount = size - leftNodesCount - 1;
+ root.left = createTree(preorder, inorder, preStart + 1, inStart, leftNodesCount);
+ root.right = createTree(preorder, inorder, preStart + leftNodesCount + 1, i + 1,
+ rightNodesCount);
+ return root;
+
+ }
+
+ private static Node createTreeOptimized(final Integer[] preorder, final Integer[] inorder,
+ final int preStart, final int inStart, final int size,
+ final Map inorderMap) {
+ if (size == 0) {
+ return null;
+ }
+
+ Node root = new Node(preorder[preStart]);
+ int i = inorderMap.get(preorder[preStart]);
+ int leftNodesCount = i - inStart;
+ int rightNodesCount = size - leftNodesCount - 1;
+ root.left = createTreeOptimized(preorder, inorder, preStart + 1, inStart,
+ leftNodesCount, inorderMap);
+ root.right = createTreeOptimized(preorder, inorder, preStart + leftNodesCount + 1,
+ i + 1, rightNodesCount, inorderMap);
+ return root;
+ }
+
+}
From 64513ff53e4ae91191a088dd7c9d734489a25d9b Mon Sep 17 00:00:00 2001
From: Amit Kumar
Date: Tue, 26 Oct 2021 11:44:26 +0530
Subject: [PATCH 0060/1552] Create a balanced binary search tree from a sorted
array (Fixes: #2706) (#2711)
Co-authored-by: Amit Kumar
---
.../Trees/CreateBSTFromSortedArray.java | 45 +++++++++++++++++++
1 file changed, 45 insertions(+)
create mode 100644 DataStructures/Trees/CreateBSTFromSortedArray.java
diff --git a/DataStructures/Trees/CreateBSTFromSortedArray.java b/DataStructures/Trees/CreateBSTFromSortedArray.java
new file mode 100644
index 000000000000..f31e7928c6b1
--- /dev/null
+++ b/DataStructures/Trees/CreateBSTFromSortedArray.java
@@ -0,0 +1,45 @@
+package DataStructures.Trees;
+
+import DataStructures.Trees.BinaryTree.Node;
+
+/**
+ * Given a sorted array. Create a balanced binary search tree from it.
+ *
+ * Steps:
+ * 1. Find the middle element of array. This will act as root
+ * 2. Use the left half recursively to create left subtree
+ * 3. Use the right half recursively to create right subtree
+ */
+public class CreateBSTFromSortedArray {
+
+ public static void main(String[] args) {
+ test(new int[]{});
+ test(new int[]{1, 2, 3});
+ test(new int[]{1, 2, 3, 4, 5});
+ test(new int[]{1, 2, 3, 4, 5, 6, 7});
+ }
+
+ private static void test(int[] array) {
+ BinaryTree root = new BinaryTree(createBst(array, 0, array.length - 1));
+ System.out.println("\n\nPreorder Traversal: ");
+ root.preOrder(root.getRoot());
+ System.out.println("\nInorder Traversal: ");
+ root.inOrder(root.getRoot());
+ System.out.println("\nPostOrder Traversal: ");
+ root.postOrder(root.getRoot());
+ }
+
+ private static Node createBst(int[] array, int start, int end) {
+ // No element left.
+ if (start > end) {
+ return null;
+ }
+ int mid = start + (end - start) / 2;
+
+ // middle element will be the root
+ Node root = new Node(array[mid]);
+ root.left = createBst(array, start, mid - 1);
+ root.right = createBst(array, mid + 1, end);
+ return root;
+ }
+}
From 9b90628a89d2c2eff2bcf907d73a8d7ef3c31959 Mon Sep 17 00:00:00 2001
From: Shivam Shrey <31056227+shivamshrey@users.noreply.github.com>
Date: Thu, 28 Oct 2021 00:26:00 +0530
Subject: [PATCH 0061/1552] Fix incorrect file extension (Fixes: #2716) (#2717)
---
DataStructures/Lists/CreateAndDetectLoop.java | 95 ++++++++++++++++
DataStructures/Lists/README.md | 2 +-
.../Lists/detect_and_create_loop.jav | 107 ------------------
3 files changed, 96 insertions(+), 108 deletions(-)
create mode 100644 DataStructures/Lists/CreateAndDetectLoop.java
delete mode 100644 DataStructures/Lists/detect_and_create_loop.jav
diff --git a/DataStructures/Lists/CreateAndDetectLoop.java b/DataStructures/Lists/CreateAndDetectLoop.java
new file mode 100644
index 000000000000..149bf51df700
--- /dev/null
+++ b/DataStructures/Lists/CreateAndDetectLoop.java
@@ -0,0 +1,95 @@
+package DataStructures.Lists;
+
+import java.util.Scanner;
+
+public class CreateAndDetectLoop {
+
+ /**
+ * Prints the linked list.
+ *
+ * @param head head node of the linked list
+ */
+ static void printList(Node head) {
+ Node cur = head;
+
+ while (cur != null) {
+ System.out.print(cur.value + " ");
+ cur = cur.next;
+ }
+ }
+
+ /**
+ * Creates a loop in the linked list.
+ * @see
+ * GeeksForGeeks: Make a loop at K-th position
+ * @param head head node of the linked list
+ * @param k position of node where loop is to be created
+ */
+ static void createLoop(Node head, int k) {
+ if (head == null)
+ return;
+ Node temp = head;
+ int count = 1;
+ while (count < k) { // Traverse the list till the kth node
+ temp = temp.next;
+ count++;
+ }
+
+ Node connectedPoint = temp;
+
+ while (temp.next != null) // Traverse remaining nodes
+ temp = temp.next;
+
+ temp.next = connectedPoint; // Connect last node to k-th element
+ }
+
+ /**
+ * Detects the presence of a loop in the linked list.
+ * @see
+ * Floyd's Cycle Detection Algorithm
+ *
+ * @param head the head node of the linked list
+ *
+ * @return true if loop exists else false
+ */
+ static boolean detectLoop(Node head) {
+ Node sptr = head;
+ Node fptr = head;
+
+ while (fptr != null && fptr.next != null) {
+ sptr = sptr.next;
+ fptr = fptr.next.next;
+ if (fptr == sptr)
+ return true;
+ }
+
+ return false;
+ }
+
+ public static void main(String[] args) {
+ SinglyLinkedList singlyLinkedList = new SinglyLinkedList();
+ Scanner sc = new Scanner(System.in);
+
+ System.out.println("Enter the number of elements to be inserted: ");
+ int n = sc.nextInt();
+ System.out.printf("Enter the %d elements: \n", n);
+ while (n-- > 0)
+ singlyLinkedList.insert(sc.nextInt());
+
+ System.out.print("Given list: ");
+ printList(singlyLinkedList.getHead());
+ System.out.println();
+
+ System.out.println("Enter the location to generate loop: ");
+ int k = sc.nextInt();
+
+ createLoop(singlyLinkedList.getHead(), k);
+
+ if (detectLoop(singlyLinkedList.getHead()))
+ System.out.println("Loop found");
+ else
+ System.out.println("No loop found");
+
+ sc.close();
+ }
+}
diff --git a/DataStructures/Lists/README.md b/DataStructures/Lists/README.md
index 544d22277667..813e1a5f84c0 100644
--- a/DataStructures/Lists/README.md
+++ b/DataStructures/Lists/README.md
@@ -25,6 +25,6 @@ The `next` variable points to the next node in the data structure and value stor
1. `CircleLinkedList.java` : A circular linked list where next pointer of last node points to first nide of linked list.
2. `SinglyLinkedList.java` : The classic case of single links.
3. `CountSinglyLinkedListRecursion.java`: Recursively counts the size of a list.
-4. `detect_and_create_loop.java` : Detect a loop in linked list
+4. `CreateAndDetectLoop.java` : Create and detect a loop in a linked list.
5. `DoublyLinkedList.java` : A modification of singly linked list which has a `prev` pointer to point to the previous node.
6. `Merge_K_SortedLinkedlist.java` : Merges K sorted linked list with mergesort (mergesort is also the most efficient sorting algorithm for linked list).
\ No newline at end of file
diff --git a/DataStructures/Lists/detect_and_create_loop.jav b/DataStructures/Lists/detect_and_create_loop.jav
deleted file mode 100644
index a4f391457d13..000000000000
--- a/DataStructures/Lists/detect_and_create_loop.jav
+++ /dev/null
@@ -1,107 +0,0 @@
-import java.util.*;
-import java.util.Scanner;
-public class LinkedList {
-
- static Node head; // head of list
-
- static class Node // Linked list Node
- {
- int data; //to store value
- Node next; //pointer
- Node(int d) {
- data = d;
- next = null;
- }
- }
-
- static int countNodes(Node ptr) //Function to count the number of nodes present
- {
- int count = 0;
- while (ptr != null) {
- ptr = ptr.next;
- count++;
- }
- return count;
- }
-
- static public void push(int new_data) // Function to inserts a new Node at front of the list
- {
-
- Node new_node = new Node(new_data); //Allocate a pointer/node and store the data
-
- new_node.next = head; // make next of new Node as head
-
- head = new_node; // Move the head to point to new Node.
- }
-
- static void printList(Node head, int total_nodes) //function to traverse through the list and print all data values
- {
- Node curr = head;
- int count = 0;
- while (count < total_nodes) {
- count++;
- System.out.print(curr.data + " ");
- curr = curr.next;
- }
- }
-
- static Node makeloop(Node head_ref, int k) {
- Node temp = head_ref;
- int count = 1;
- while (count < k) //traverrse the list till point is found
- {
- temp = temp.next;
- count++;
- }
-
- Node connected_point = temp;
-
- while (temp.next != null) // traverse remaining nodes
- temp = temp.next;
-
- temp.next = connected_point; //connect last node to k-th element
- return head_ref;
- }
-
- static boolean detectLoop(Node h) //Function to detect loop, retuens true if loop is in linked list else returns false.
- {
- HashSet < Node > traverse = new HashSet < Node > ();
- while (n != null) {
-
- if (traverse.contains(n)) //if the hash a;ready contains a record of the node encountered true is returned as a loop isdetected
- return true;
-
- traverse.add(n);
- n = n.next;
- }
- return false;
- }
-
- public static void main(String[] args) {
- LinkedList l = new LinkedList();
-
- Scanner sc = new Scanner(System.in);
-
- print("Enter elements in the list, to stop entering press any alphabetical key");
- while (true) {
- try {
- i = sc.nextInt();
- l.push(i);
- } catch (Exception e) {
- System.out.println("Creating loop for run");
- }
- }
- System.out.println("Enter the location to generate loop");
- int k = sc.nextInt()
- System.out.print("Given list");
- printList(head, total_nodes);
- head = makeloop(head, k);
- System.out.print("Modified list with loop");
- printList(head, total_nodes);
-
- if (detectLoop(head))
- System.out.println("Loop found");
- else
- System.out.println("No Loop");
- }
-}
From 1899d2a43992d24bf41ca88f03c6b97ae1b887e0 Mon Sep 17 00:00:00 2001
From: Pratik Padalia
Date: Thu, 28 Oct 2021 00:29:23 +0530
Subject: [PATCH 0062/1552] Add Upper Bound Search Algorithm (#2722)
Co-authored-by: Pratik
---
Searches/UpperBound.java | 95 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 95 insertions(+)
create mode 100644 Searches/UpperBound.java
diff --git a/Searches/UpperBound.java b/Searches/UpperBound.java
new file mode 100644
index 000000000000..6f895fcafde0
--- /dev/null
+++ b/Searches/UpperBound.java
@@ -0,0 +1,95 @@
+package Searches;
+
+import static java.lang.String.format;
+
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.stream.IntStream;
+
+/**
+ * The UpperBound method is used to return an index pointing to the first element in the range
+ * [first, last) which has a value greater than val, or the last index if no such element exists
+ * i.e. the index of the next smallest number just greater than that number. If there are multiple
+ * values that are equal to val it returns the index of the first such value.
+ *
+ * This is an extension of BinarySearch.
+ *
+ *
Worst-case performance O(log n) Best-case performance O(1) Average performance O(log n)
+ * Worst-case space complexity O(1)
+ *
+ * @author Pratik Padalia (https://github.com/15pratik)
+ * @see SearchAlgorithm
+ * @see BinarySearch
+ */
+class UpperBound implements SearchAlgorithm {
+
+ // Driver Program
+ public static void main(String[] args) {
+ // Just generate data
+ Random r = ThreadLocalRandom.current();
+
+ int size = 100;
+ int maxElement = 100000;
+
+ Integer[] integers =
+ IntStream.generate(() -> r.nextInt(maxElement))
+ .limit(size)
+ .sorted()
+ .boxed()
+ .toArray(Integer[]::new);
+
+ // The element for which the upper bound is to be found
+ int val = integers[r.nextInt(size - 1)] + 1;
+
+ UpperBound search = new UpperBound();
+ int atIndex = search.find(integers, val);
+
+ System.out.println(
+ format(
+ "Val: %d. Upper Bound Found %d at index %d. An array length %d",
+ val, integers[atIndex], atIndex, size));
+
+ boolean toCheck = integers[atIndex] > val || integers[size - 1] < val;
+ System.out.println(
+ format(
+ "Upper Bound found at an index: %d. Is greater or max element: %b", atIndex, toCheck));
+ }
+
+ /**
+ * @param array is an array where the UpperBound value is to be found
+ * @param key is an element for which the UpperBound is to be found
+ * @param is any comparable type
+ * @return index of the UpperBound element
+ */
+ @Override
+ public > int find(T[] array, T key) {
+ return search(array, key, 0, array.length - 1);
+ }
+
+ /**
+ * This method implements the Generic Binary Search
+ *
+ * @param array The array to make the binary search
+ * @param key The number you are looking for
+ * @param left The lower bound
+ * @param right The upper bound
+ * @return the location of the key
+ */
+ private > int search(T[] array, T key, int left, int right) {
+ if (right <= left) {
+ return left;
+ }
+
+ // find median
+ int median = (left + right) >>> 1;
+ int comp = key.compareTo(array[median]);
+
+ if (comp < 0) {
+ // key is smaller, median position can be a possible solution
+ return search(array, key, left, median);
+ } else {
+ // key we are looking is greater, so we must look on the right of median position
+ return search(array, key, median + 1, right);
+ }
+ }
+}
From b2de5c7f1eda5ab1e48749dfba41acb001cc328a Mon Sep 17 00:00:00 2001
From: Artem Boiarshinov <54187376+Boiarshinov@users.noreply.github.com>
Date: Wed, 27 Oct 2021 22:01:53 +0300
Subject: [PATCH 0063/1552] Add description for Sieve of Eratosthenes algorithm
(Fixes: #2724) (#2725)
---
Others/SieveOfEratosthenes.java | 74 +++++++++++++++++++++++----------
1 file changed, 53 insertions(+), 21 deletions(-)
diff --git a/Others/SieveOfEratosthenes.java b/Others/SieveOfEratosthenes.java
index f3759d2fdb56..a4293cc3439b 100644
--- a/Others/SieveOfEratosthenes.java
+++ b/Others/SieveOfEratosthenes.java
@@ -1,44 +1,76 @@
package Others;
-/** @author Varun Upadhyay (https://github.com/varunu28) */
+import java.util.Arrays;
+
+/**
+ * Sieve of Eratosthenes is an ancient algorithm for finding all prime numbers up to any given limit.
+ * It does so by iteratively marking as composite (i.e., not prime) the multiples of each prime,
+ * starting with the first prime number, 2.
+ * The multiples of a given prime are generated as a sequence of numbers starting from that prime,
+ * with constant difference between them that is equal to that prime.
+ * This is the sieve's key distinction from using trial division to sequentially test each
+ * candidate number for divisibility by each prime.
+ * Once all the multiples of each discovered prime have been marked as composites, the remaining
+ * unmarked numbers are primes.
+ *
+ * Poetry about Sieve of Eratosthenes:
+ *
Sift the Two's and Sift the Three's:
+ * The Sieve of Eratosthenes.
+ * When the multiples sublime,
+ * The numbers that remain are Prime.
+ *
+ * @see Wiki
+ */
public class SieveOfEratosthenes {
/**
- * This method implements the Sieve of Eratosthenes Algorithm
- *
- * @param n The number till which we have to check for prime Prints all the prime numbers till n
+ * @param n The number till which we have to check for prime Prints all the prime numbers till n.
+ * Should be more than 1.
+ * @return array of all prime numbers between 0 to n
*/
- public static void findPrimesTillN(int n) {
- int[] arr = new int[n + 1];
-
- for (int i = 0; i <= n; i++) {
- arr[i] = 1;
- }
+ public static int[] findPrimesTill(int n) {
+ // Create array where index is number and value is flag - is that number a prime or not.
+ // size of array is n + 1 cause in Java array indexes starts with 0
+ Type[] numbers = new Type[n + 1];
- arr[0] = arr[1] = 0;
+ // Start with assumption that all numbers except 0 and 1 are primes.
+ Arrays.fill(numbers, Type.PRIME);
+ numbers[0] = numbers[1] = Type.NOT_PRIME;
- for (int i = 2; i <= Math.sqrt(n); i++) {
- if (arr[i] == 1) {
+ double cap = Math.sqrt(n);
+ // Main algorithm: mark all numbers which are multiples of some other values as not prime
+ for (int i = 2; i <= cap; i++) {
+ if (numbers[i] == Type.PRIME) {
for (int j = 2; i * j <= n; j++) {
- arr[i * j] = 0;
+ numbers[i * j] = Type.NOT_PRIME;
}
}
}
+ //Write all primes to result array
+ int primesCount = (int) Arrays.stream(numbers)
+ .filter(element -> element == Type.PRIME)
+ .count();
+ int[] primes = new int[primesCount];
+
+ int primeIndex = 0;
for (int i = 0; i < n + 1; i++) {
- if (arr[i] == 1) {
- System.out.print(i + " ");
+ if(numbers[i] == Type.PRIME) {
+ primes[primeIndex++] = i;
}
}
- System.out.println();
+ return primes;
+ }
+
+ private enum Type {
+ PRIME, NOT_PRIME
}
- // Driver Program
public static void main(String[] args) {
int n = 100;
-
- // Prints 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
- findPrimesTillN(n);
+ System.out.println("Searching for all primes from zero to " + n);
+ int[] primes = findPrimesTill(n);
+ System.out.println("Found: " + Arrays.toString(primes));
}
}
From ad380dcaa4721e5bad5ba4517d380dec2b697ec9 Mon Sep 17 00:00:00 2001
From: Shraddha <42699578+shraddhavp@users.noreply.github.com>
Date: Thu, 28 Oct 2021 00:33:51 +0530
Subject: [PATCH 0064/1552] Add Boyer moore voting algo (#2726)
---
Others/BoyerMoore.java | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
create mode 100644 Others/BoyerMoore.java
diff --git a/Others/BoyerMoore.java b/Others/BoyerMoore.java
new file mode 100644
index 000000000000..68f6aa6fde9d
--- /dev/null
+++ b/Others/BoyerMoore.java
@@ -0,0 +1,40 @@
+/* this Code is the illustration of Boyer moore's voting algorithm to
+find the majority element is an array that appears more than n/2 times in an array
+where "n" is the length of the array.
+For more information on the algorithm refer https://en.wikipedia.org/wiki/Boyer%E2%80%93Moore_majority_vote_algorithm
+ */
+package Others;
+import java.util.*;
+
+public class BoyerMoore {
+ public static int findmajor(int [] a){
+int count=0; int cand=-1;
+for(int i=0;i (a.length / 2))
+ return cand;
+ return -1;
+}
+ public static void main(String args[]){
+ Scanner input=new Scanner(System.in);
+ int n=input.nextInt();
+ int a[]=new int[n];
+ for(int i=0;i
Date: Wed, 27 Oct 2021 22:19:09 +0300
Subject: [PATCH 0065/1552] Add nearest right neighbor (#2574)
---
DataStructures/Trees/nearestRightKey.java | 84 +++++++++++++++++++++++
1 file changed, 84 insertions(+)
create mode 100644 DataStructures/Trees/nearestRightKey.java
diff --git a/DataStructures/Trees/nearestRightKey.java b/DataStructures/Trees/nearestRightKey.java
new file mode 100644
index 000000000000..228bf470d809
--- /dev/null
+++ b/DataStructures/Trees/nearestRightKey.java
@@ -0,0 +1,84 @@
+package DataStructures.NRKTrees;
+
+import java.util.Scanner;
+import java.util.concurrent.ThreadLocalRandom;
+
+class Main {
+
+ public static void main(String[] args) {
+ NRKTree root = BuildTree();
+ Scanner sc = new Scanner(System.in);
+ System.out.print("Enter first number: ");
+ int inputX0 = sc.nextInt();
+ int toPrint = nearestRightKey(root, inputX0);
+ System.out.println("Key: " + toPrint);
+ }
+
+ public static NRKTree BuildTree() {
+ int randomX = ThreadLocalRandom.current().nextInt(0, 100 + 1);
+ NRKTree root = new NRKTree(null, null, randomX);
+
+ for (int i = 0; i < 1000; i++) {
+ randomX = ThreadLocalRandom.current().nextInt(0, 100 + 1);
+ root = root.insertKey(root, randomX);
+ }
+
+ return root;
+ }
+
+ public static int nearestRightKey(NRKTree root, int x0) {
+ //Check whether tree is empty
+ if(root == null){
+ return 0;
+ }
+ else {
+ if(root.data - x0 > 0){
+ // Go left
+ int temp = nearestRightKey(root.left, x0);
+ if(temp == 0){
+ return root.data;
+ }
+ return temp;
+ } else {
+ // Go right
+ return nearestRightKey(root.right, x0);
+ }
+
+ }
+ }
+
+}
+
+
+class NRKTree {
+
+ public NRKTree left;
+ public NRKTree right;
+ public int data;
+
+ public NRKTree(int x) {
+ this.left = null;
+ this.right = null;
+ this.data = x;
+ }
+
+ public NRKTree(NRKTree right, NRKTree left, int x) {
+ this.left = left;
+ this.right = right;
+ this.data = x;
+ }
+
+ public NRKTree insertKey(NRKTree current, int value) {
+ if (current == null) {
+ return new NRKTree(value);
+ }
+
+ if (value < current.data) {
+ current.left = insertKey(current.left, value);
+ } else if (value > current.data) {
+ current.right = insertKey(current.right, value);
+ }
+
+ return current;
+ }
+}
From 6934c53c0400e1d3158014dfeb984e629c0bc8fb Mon Sep 17 00:00:00 2001
From: januslinhc
Date: Fri, 29 Oct 2021 00:58:58 +0800
Subject: [PATCH 0066/1552] Add MRU Cache (#2738)
---
DIRECTORY.md | 8 ++
DataStructures/Caches/MRUCache.java | 179 ++++++++++++++++++++++++++++
2 files changed, 187 insertions(+)
create mode 100644 DataStructures/Caches/MRUCache.java
diff --git a/DIRECTORY.md b/DIRECTORY.md
index 4fd29a368cf4..3a2ee7bd7668 100644
--- a/DIRECTORY.md
+++ b/DIRECTORY.md
@@ -3,6 +3,7 @@
* [IIRFilter](https://github.com/TheAlgorithms/Java/blob/master/AudioFilters/IIRFilter.java)
## Backtracking
+ * [KnightsTour](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/KnightsTour.java)
* [NQueens](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/NQueens.java)
* [PowerSum](https://github.com/TheAlgorithms/Java/blob/master/Backtracking/PowerSum.java)
@@ -48,6 +49,7 @@
* [CircularBuffer](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Buffers/CircularBuffer.java)
* Caches
* [LRUCache](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Caches/LRUCache.java)
+ * [MRUCache](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Caches/MRUCache.java)
* DisjointSets
* [DisjointSets](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/DisjointSets.java)
* [Node](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/DisjointSets/Node.java)
@@ -82,6 +84,7 @@
* Lists
* [CircleLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CircleLinkedList.java)
* [CountSinglyLinkedListRecursion](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CountSinglyLinkedListRecursion.java)
+ * [CreateAndDetectLoop](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CreateAndDetectLoop.java)
* [CursorLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/CursorLinkedList.java)
* [DoublyLinkedList](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/DoublyLinkedList.java)
* [Merge K SortedLinkedlist](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Lists/Merge_K_SortedLinkedlist.java)
@@ -113,11 +116,14 @@
* [BSTRecursive](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/BSTRecursive.java)
* [BSTRecursiveGeneric](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/BSTRecursiveGeneric.java)
* [CeilInBinarySearchTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CeilInBinarySearchTree.java)
+ * [CreateBinaryTreeFromInorderPreorder](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CreateBinaryTreeFromInorderPreorder.java)
+ * [CreateBSTFromSortedArray](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/CreateBSTFromSortedArray.java)
* [FenwickTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/FenwickTree.java)
* [GenericTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/GenericTree.java)
* [LCA](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LCA.java)
* [LevelOrderTraversal](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversal.java)
* [LevelOrderTraversalQueue](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/LevelOrderTraversalQueue.java)
+ * [nearestRightKey](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/nearestRightKey.java)
* [PrintTopViewofTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/PrintTopViewofTree.java)
* [RedBlackBST](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/RedBlackBST.java)
* [SegmentTree](https://github.com/TheAlgorithms/Java/blob/master/DataStructures/Trees/SegmentTree.java)
@@ -253,6 +259,7 @@
## Others
* [BestFit](https://github.com/TheAlgorithms/Java/blob/master/Others/BestFit.java)
* [BFPRT](https://github.com/TheAlgorithms/Java/blob/master/Others/BFPRT.java)
+ * [BoyerMoore](https://github.com/TheAlgorithms/Java/blob/master/Others/BoyerMoore.java)
* [BrianKernighanAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/Others/BrianKernighanAlgorithm.java)
* [CountChar](https://github.com/TheAlgorithms/Java/blob/master/Others/CountChar.java)
* [CountWords](https://github.com/TheAlgorithms/Java/blob/master/Others/CountWords.java)
@@ -317,6 +324,7 @@
* [SquareRootBinarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/SquareRootBinarySearch.java)
* [TernarySearch](https://github.com/TheAlgorithms/Java/blob/master/Searches/TernarySearch.java)
* [UnionFind](https://github.com/TheAlgorithms/Java/blob/master/Searches/UnionFind.java)
+ * [UpperBound](https://github.com/TheAlgorithms/Java/blob/master/Searches/UpperBound.java)
## Sorts
* [BitonicSort](https://github.com/TheAlgorithms/Java/blob/master/Sorts/BitonicSort.java)
diff --git a/DataStructures/Caches/MRUCache.java b/DataStructures/Caches/MRUCache.java
new file mode 100644
index 000000000000..e31564775a3f
--- /dev/null
+++ b/DataStructures/Caches/MRUCache.java
@@ -0,0 +1,179 @@
+package DataStructures.Caches;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Most recently used (MRU)
+ *
+ * In contrast to Least Recently Used (LRU), MRU discards the most recently used items first.
+ * https://en.wikipedia.org/wiki/Cache_replacement_policies#Most_recently_used_(MRU)
+ *
+ * @param key type
+ * @param value type
+ */
+public class MRUCache {
+ private final Map> data = new HashMap<>();
+ private Entry head;
+ private Entry tail;
+ private int cap;
+ private static final int DEFAULT_CAP = 100;
+
+ public MRUCache() {
+ setCapacity(DEFAULT_CAP);
+ }
+
+ private void setCapacity(int newCapacity) {
+ checkCapacity(newCapacity);
+ for (int i = data.size(); i > newCapacity; i--) {
+ Entry evicted = evict();
+ data.remove(evicted.getKey());
+ }
+ this.cap = newCapacity;
+ }
+
+
+ private void checkCapacity(int capacity) {
+ if (capacity <= 0) {
+ throw new RuntimeException("capacity must greater than 0!");
+ }
+ }
+
+ private Entry evict() {
+ if (head == null) {
+ throw new RuntimeException("cache cannot be empty!");
+ }
+ final Entry evicted = this.tail;
+ tail = evicted.getPreEntry();
+ tail.setNextEntry(null);
+ evicted.setNextEntry(null);
+ return evicted;
+ }
+
+ public MRUCache(int cap) {
+ setCapacity(cap);
+ }
+
+ public V get(K key) {
+ if (!data.containsKey(key)) {
+ return null;
+ }
+ final Entry entry = data.get(key);
+ moveEntryToLast(entry);
+ return entry.getValue();
+ }
+
+ public void put(K key, V value) {
+ if (data.containsKey(key)) {
+ final Entry exitingEntry = data.get(key);
+ exitingEntry.setValue(value);
+ moveEntryToLast(exitingEntry);
+ return;
+ }
+ Entry newEntry;
+ if (data.size() == cap) {
+ newEntry = evict();
+ data.remove(newEntry.getKey());
+ } else {
+ newEntry = new Entry<>();
+ }
+ newEntry.setKey(key);
+ newEntry.setValue(value);
+ addNewEntry(newEntry);
+ data.put(key, newEntry);
+ }
+
+ private void addNewEntry(Entry newEntry) {
+ if (data.isEmpty()) {
+ head = newEntry;
+ tail = newEntry;
+ return;
+ }
+ tail.setNextEntry(newEntry);
+ newEntry.setPreEntry(tail);
+ newEntry.setNextEntry(null);
+ tail = newEntry;
+ }
+
+ private void moveEntryToLast(Entry entry) {
+ if (tail == entry) {
+ return;
+ }
+ final Entry preEntry = entry.getPreEntry();
+ final Entry nextEntry = entry.getNextEntry();
+ if (preEntry != null) {
+ preEntry.setNextEntry(nextEntry);
+ }
+ if (nextEntry != null) {
+ nextEntry.setPreEntry(preEntry);
+ }
+ if (head == entry) {
+ head = nextEntry;
+ }
+ tail.setNextEntry(entry);
+ entry.setPreEntry(tail);
+ entry.setNextEntry(null);
+ tail = entry;
+ }
+
+ static final class Entry {
+ private Entry preEntry;
+ private Entry nextEntry;
+ private I key;
+ private J value;
+
+ public Entry() {
+ }
+
+ public Entry(Entry preEntry, Entry nextEntry, I key, J value) {
+ this.preEntry = preEntry;
+ this.nextEntry = nextEntry;
+ this.key = key;
+ this.value = value;
+ }
+
+ public Entry getPreEntry() {
+ return preEntry;
+ }
+
+ public void setPreEntry(Entry preEntry) {
+ this.preEntry = preEntry;
+ }
+
+ public Entry getNextEntry() {
+ return nextEntry;
+ }
+
+ public void setNextEntry(Entry nextEntry) {
+ this.nextEntry = nextEntry;
+ }
+
+ public I getKey() {
+ return key;
+ }
+
+ public void setKey(I key) {
+ this.key = key;
+ }
+
+ public J getValue() {
+ return value;
+ }
+
+ public void setValue(J value) {
+ this.value = value;
+ }
+ }
+
+ public static void main(String[] args) {
+ final MRUCache cache = new MRUCache<>(2);
+ cache.put("Key1", 1);
+ cache.put("Key2", 2);
+ cache.put("Key3", 3);
+ cache.put("Key4", 4);
+ System.out.println("getValue(Key1): " + cache.get("Key1"));
+ System.out.println("getValue(Key2): " + cache.get("Key2"));
+ System.out.println("getValue(Key3): " + cache.get("Key3"));
+ System.out.println("getValue(Key4): " + cache.get("Key4"));
+ }
+}
From 9ff553e0a35ac2e4a80f5fe8e2dd96d8c8988cb8 Mon Sep 17 00:00:00 2001
From: Sneha B <57147597+Sneha421@users.noreply.github.com>
Date: Thu, 28 Oct 2021 22:31:59 +0530
Subject: [PATCH 0067/1552] Add Three Sum Problem (#2741)
---
Misc/ThreeSumProblem.java | 109 ++++++++++++++++++++++++++++++++++++++
Misc/TwoSumProblem.java | 1 -
2 files changed, 109 insertions(+), 1 deletion(-)
create mode 100644 Misc/ThreeSumProblem.java
diff --git a/Misc/ThreeSumProblem.java b/Misc/ThreeSumProblem.java
new file mode 100644
index 000000000000..a5ccae862ddc
--- /dev/null
+++ b/Misc/ThreeSumProblem.java
@@ -0,0 +1,109 @@
+import java.util.*;
+public class ThreeSumProblem {
+ public static void main(String args[])
+ {
+ Scanner scan = new Scanner(System.in);
+ System.out.print("Enter the target sum ");
+ int ts= scan.nextInt();
+ System.out.print("Enter the number of elements in the array ");
+ int n = scan.nextInt();
+ System.out.println("Enter all your array elements:");
+ int arr[]= new int[n];
+ for(int i=0;i> BruteForce(int[] nums,int target) {
+ List> arr = new ArrayList>();
+
+ for(int i=0;i temp = new ArrayList<>();
+ temp.add(nums[i]);
+ temp.add(nums[j]);
+ temp.add(nums[k]);
+ Collections.sort(temp);
+ arr.add(temp);
+ }
+
+
+ }
+ }
+ }
+ arr = new ArrayList>(new LinkedHashSet>(arr));
+ return arr;
+ }
+ public List> TwoPointer(int[] nums, int target) {
+ Arrays.sort(nums);
+ List> arr = new ArrayList>();
+ int start=0;
+ int end=0;
+ int i = 0;
+ while(i temp = new ArrayList<>();
+ temp.add(nums[i]);
+ temp.add(nums[start]);
+ temp.add(nums[end]);
+ arr.add(temp);
+ start++;
+ end--;
+ }
+ else if (nums[start]+nums[end]+nums[i]> set = new LinkedHashSet>(arr);
+ return new ArrayList>(set);
+ }
+ public List> Hashmap(int[] nums, int target) {
+ Arrays.sort(nums);
+ Set> ts = new HashSet();
+ HashMap hm = new HashMap<>();
+
+ for(int i=0;ij)
+ {
+ List temp = new ArrayList<>();
+ temp.add(nums[i]);
+ temp.add(nums[j]);
+ temp.add(t);
+ ts.add(temp);
+ }
+ }
+ }
+ return new ArrayList(ts);
+ }
+
+}
+
diff --git a/Misc/TwoSumProblem.java b/Misc/TwoSumProblem.java
index 0bea06f3901f..620f5d883c07 100644
--- a/Misc/TwoSumProblem.java
+++ b/Misc/TwoSumProblem.java
@@ -1,5 +1,4 @@
package Misc;
-
import java.util.*;
import java.util.stream.Collectors;
From 447c5fa578a98b0af85bf63969b48993f8ddf38e Mon Sep 17 00:00:00 2001
From: Limbad Yash <56826569+limbad-YK@users.noreply.github.com>
Date: Thu, 28 Oct 2021 22:33:31 +0530
Subject: [PATCH 0068/1552] Add Longest Alternating Subsequence (#2743)
---
.../LongestAlternatingSubsequence.java | 68 +++++++++++++++++++
1 file changed, 68 insertions(+)
create mode 100644 DynamicProgramming/LongestAlternatingSubsequence.java
diff --git a/DynamicProgramming/LongestAlternatingSubsequence.java b/DynamicProgramming/LongestAlternatingSubsequence.java
new file mode 100644
index 000000000000..3551edf0262e
--- /dev/null
+++ b/DynamicProgramming/LongestAlternatingSubsequence.java
@@ -0,0 +1,68 @@
+/*
+
+ * Problem Statement: -
+ * Find Longest Alternating Subsequence
+
+ * A sequence {x1, x2, .. xn} is alternating sequence if its elements satisfy one of the following relations :
+
+ x1 < x2 > x3 < x4 > x5 < …. xn or
+ x1 > x2 < x3 > x4 < x5 > …. xn
+*/
+
+import java.io.*;
+
+public class LongestAlternatingSubsequence {
+
+ /* Function to return longest alternating subsequence length*/
+ static int AlternatingLength(int arr[], int n){
+ /*
+
+ las[i][0] = Length of the longest
+ alternating subsequence ending at
+ index i and last element is
+ greater than its previous element
+
+ las[i][1] = Length of the longest
+ alternating subsequence ending at
+ index i and last element is
+ smaller than its previous
+ element
+
+ */
+ int las[][] = new int[n][2]; // las = LongestAlternatingSubsequence
+
+ for (int i = 0; i < n; i++)
+ las[i][0] = las[i][1] = 1;
+
+ int result = 1; // Initialize result
+
+ /* Compute values in bottom up manner */
+ for (int i = 1; i < n; i++){
+
+ /* Consider all elements as previous of arr[i]*/
+ for (int j = 0; j < i; j++){
+
+ /* If arr[i] is greater, then check with las[j][1] */
+ if (arr[j] < arr[i] && las[i][0] < las[j][1] + 1)
+ las[i][0] = las[j][1] + 1;
+
+ /* If arr[i] is smaller, then check with las[j][0]*/
+ if( arr[j] > arr[i] && las[i][1] < las[j][0] + 1)
+ las[i][1] = las[j][0] + 1;
+ }
+
+ /* Pick maximum of both values at index i */
+ if (result < Math.max(las[i][0], las[i][1]))
+ result = Math.max(las[i][0], las[i][1]);
+ }
+
+ return result;
+ }
+
+ public static void main(String[] args)
+ {
+ int arr[] = { 10, 22, 9, 33, 49,50, 31, 60 };
+ int n = arr.length;
+ System.out.println("Length of Longest "+"alternating subsequence is " +AlternatingLength(arr, n));
+ }
+}
From 7858187d59c7189c05b5833162fda8a2c64b5bb4 Mon Sep 17 00:00:00 2001
From: Rahul Chhabra
Date: Thu, 28 Oct 2021 22:35:44 +0530
Subject: [PATCH 0069/1552] Add Solver For Linear Diophantine Equations (#2744)
---
Maths/LinearDiophantineEquationsSolver.java | 143 ++++++++++++++++++++
1 file changed, 143 insertions(+)
create mode 100644 Maths/LinearDiophantineEquationsSolver.java
diff --git a/Maths/LinearDiophantineEquationsSolver.java b/Maths/LinearDiophantineEquationsSolver.java
new file mode 100644
index 000000000000..09837cc9037c
--- /dev/null
+++ b/Maths/LinearDiophantineEquationsSolver.java
@@ -0,0 +1,143 @@
+package Maths;
+
+import java.util.Objects;
+
+public final class LinearDiophantineEquationsSolver {
+
+ public static void main(String[] args) {
+ // 3x + 4y = 7
+ final var toSolve = new Equation(3, 4, 7);
+ System.out.println(findAnySolution(toSolve));
+ }
+
+ public static Solution findAnySolution(final Equation equation) {
+ if (equation.a() == 0 && equation.b() == 0 && equation.c() == 0) {
+ return Solution.INFINITE_SOLUTIONS;
+ }
+ final var stub = new GcdSolutionWrapper(0, new Solution(0, 0));
+ final var gcdSolution = gcd(equation.a(), equation.b(), stub);
+ if (equation.c() % gcdSolution.getGcd() != 0) {
+ return Solution.NO_SOLUTION;
+ }
+ final var toReturn = new Solution(0, 0);
+ var xToSet = stub.getSolution().getX() * (equation.c() / stub.getGcd());
+ var yToSet = stub.getSolution().getY() * (equation.c() / stub.getGcd());
+ toReturn.setX(xToSet);
+ toReturn.setY(yToSet);
+ return toReturn;
+ }
+
+ private static GcdSolutionWrapper gcd(final int a, final int b, final GcdSolutionWrapper previous) {
+ if (b == 0) {
+ return new GcdSolutionWrapper(a, new Solution(1, 0));
+ }
+ // stub wrapper becomes the `previous` of the next recursive call
+ final var stubWrapper = new GcdSolutionWrapper(0, new Solution(0, 0));
+ final var next = /* recursive call */ gcd(b, a % b, stubWrapper);
+ previous.getSolution().setX(next.getSolution().getY());
+ previous.getSolution().setY(next.getSolution().getX() - (a / b) * (next.getSolution().getY()));
+ previous.setGcd(next.getGcd());
+ return new GcdSolutionWrapper(next.getGcd(), previous.getSolution());
+ }
+
+ public static final class Solution {
+ public static final Solution NO_SOLUTION = new Solution(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ public static final Solution INFINITE_SOLUTIONS = new Solution(Integer.MIN_VALUE, Integer.MIN_VALUE);
+ private int x;
+ private int y;
+
+ public Solution(int x, int y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public int getX() {
+ return x;
+ }
+
+ public int getY() {
+ return y;
+ }
+
+ public void setX(int x) {
+ this.x = x;
+ }
+
+ public void setY(int y) {
+ this.y = y;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) return true;
+ if (obj == null || obj.getClass() != this.getClass()) return false;
+ var that = (Solution) obj;
+ return this.x == that.x &&
+ this.y == that.y;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(x, y);
+ }
+
+ @Override
+ public String toString() {
+ return "Solution[" +
+ "x=" + x + ", " +
+ "y=" + y + ']';
+ }
+
+ }
+
+ public record Equation(int a, int b, int c) {
+ }
+
+ public static final class GcdSolutionWrapper {
+ private int gcd;
+ private Solution solution;
+
+ public GcdSolutionWrapper(int gcd, Solution solution) {
+ this.gcd = gcd;
+ this.solution = solution;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) return true;
+ if (obj == null || obj.getClass() != this.getClass()) return false;
+ var that = (GcdSolutionWrapper) obj;
+ return this.gcd == that.gcd &&
+ Objects.equals(this.solution, that.solution);
+ }
+
+ public int getGcd() {
+ return gcd;
+ }
+
+ public void setGcd(int gcd) {
+ this.gcd = gcd;
+ }
+
+ public Solution getSolution() {
+ return solution;
+ }
+
+ public void setSolution(Solution solution) {
+ this.solution = solution;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(gcd, solution);
+ }
+
+ @Override
+ public String toString() {
+ return "GcdSolutionWrapper[" +
+ "gcd=" + gcd + ", " +
+ "solution=" + solution + ']';
+ }
+
+ }
+}
From 4db7a0c77e77378849fd2715842805c4b3c86c99 Mon Sep 17 00:00:00 2001
From: Shraddha <42699578+shraddhavp@users.noreply.github.com>
Date: Fri, 29 Oct 2021 10:24:11 +0530
Subject: [PATCH 0070/1552] Adde Dutch National Flag Algorithm (#2728)
---
Misc/Sort012D.java | 53 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 53 insertions(+)
create mode 100644 Misc/Sort012D.java
diff --git a/Misc/Sort012D.java b/Misc/Sort012D.java
new file mode 100644
index 000000000000..3d9785bad673
--- /dev/null
+++ b/Misc/Sort012D.java
@@ -0,0 +1,53 @@
+package Misc;
+import java.util.*;
+/**
+The array is divided into four sections:
+a[1..Lo-1] zeroes
+a[Lo..Mid-1] ones
+a[Mid..Hi] unknown
+a[Hi+1..N] twos
+If array [mid] =0, then swap array [mid] with array [low] and increment both pointers once.
+If array [mid] = 1, then no swapping is required. Increment mid pointer once.
+If array [mid] = 2, then we swap array [mid] with array [high] and decrement the high pointer once.
+For more information on the Dutch national flag algorithm refer https://en.wikipedia.org/wiki/Dutch_national_flag_problem
+*/
+public class Sort012D {
+ public static void main(String args[]) {
+ Scanner np = new Scanner(System.in);
+ int n = np.nextInt();
+ int a[] = new int[n];
+ for (int i = 0; i < n; i++) {
+ a[i] = np.nextInt();
+ }
+ sort012(a);}
+
+ public static void sort012(int[]a){
+ int l = 0;
+ int h = a.length - 1;
+ int mid = 0;
+ int temp ;
+ while (mid <= h) {
+ switch (a[mid]) {
+ case 0: {
+ temp = a[l];
+ a[l] = a[mid];
+ a[mid] = temp;
+ l++;
+ mid++;
+ break;}
+ case 1:
+ mid++;
+ break;
+ case 2: {
+ temp = a[mid];
+ a[mid] = a[h];
+ a[h] = temp;
+ h--;
+ break;
+ }
+ }
+ }
+ System.out.println("the Sorted array is ");
+ for (int i = 0; i < a.length; i++)
+ System.out.print(+a[i] + " "); }
+}
From 0503c466800673c21a4a61553db5f443d8421963 Mon Sep 17 00:00:00 2001
From: Shikhar Chandra <47221817+SHIKHAR-CHANDRA@users.noreply.github.com>
Date: Fri, 29 Oct 2021 10:46:26 +0530
Subject: [PATCH 0071/1552] Add Huffman Compression (#2753)
---
Others/Huffman.java | 135 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 135 insertions(+)
create mode 100644 Others/Huffman.java
diff --git a/Others/Huffman.java b/Others/Huffman.java
new file mode 100644
index 000000000000..43366046bdd4
--- /dev/null
+++ b/Others/Huffman.java
@@ -0,0 +1,135 @@
+import java.util.PriorityQueue;
+import java.util.Scanner;
+import java.util.Comparator;
+
+// node class is the basic structure
+// of each node present in the Huffman - tree.
+class HuffmanNode {
+
+ int data;
+ char c;
+
+ HuffmanNode left;
+ HuffmanNode right;
+}
+
+// comparator class helps to compare the node
+// on the basis of one of its attribute.
+// Here we will be compared
+// on the basis of data values of the nodes.
+class MyComparator implements Comparator {
+ public int compare(HuffmanNode x, HuffmanNode y)
+ {
+
+ return x.data - y.data;
+ }
+}
+
+public class Huffman {
+
+ // recursive function to print the
+ // huffman-code through the tree traversal.
+ // Here s is the huffman - code generated.
+ public static void printCode(HuffmanNode root, String s)
+ {
+
+ // base case; if the left and right are null
+ // then its a leaf node and we print
+ // the code s generated by traversing the tree.
+ if (root.left
+ == null
+ && root.right
+ == null
+ && Character.isLetter(root.c)) {
+
+ // c is the character in the node
+ System.out.println(root.c + ":" + s);
+
+ return;
+ }
+
+ // if we go to left then add "0" to the code.
+ // if we go to the right add"1" to the code.
+
+ // recursive calls for left and
+ // right sub-tree of the generated tree.
+ printCode(root.left, s + "0");
+ printCode(root.right, s + "1");
+ }
+
+ // main function
+ public static void main(String[] args)
+ {
+
+ Scanner s = new Scanner(System.in);
+
+ // number of characters.
+ int n = 6;
+ char[] charArray = { 'a', 'b', 'c', 'd', 'e', 'f' };
+ int[] charfreq = { 5, 9, 12, 13, 16, 45 };
+
+ // creating a priority queue q.
+ // makes a min-priority queue(min-heap).
+ PriorityQueue q
+ = new PriorityQueue(n, new MyComparator());
+
+ for (int i = 0; i < n; i++) {
+
+ // creating a Huffman node object
+ // and add it to the priority queue.
+ HuffmanNode hn = new HuffmanNode();
+
+ hn.c = charArray[i];
+ hn.data = charfreq[i];
+
+ hn.left = null;
+ hn.right = null;
+
+ // add functions adds
+ // the huffman node to the queue.
+ q.add(hn);
+ }
+
+ // create a root node
+ HuffmanNode root = null;
+
+ // Here we will extract the two minimum value
+ // from the heap each time until
+ // its size reduces to 1, extract until
+ // all the nodes are extracted.
+ while (q.size() > 1) {
+
+ // first min extract.
+ HuffmanNode x = q.peek();
+ q.poll();
+
+ // second min extarct.
+ HuffmanNode y = q.peek();
+ q.poll();
+
+ // new node f which is equal
+ HuffmanNode f = new HuffmanNode();
+
+ // to the sum of the frequency of the two nodes
+ // assigning values to the f node.
+ f.data = x.data + y.data;
+ f.c = '-';
+
+ // first extracted node as left child.
+ f.left = x;
+
+ // second extracted node as the right child.
+ f.right = y;
+
+ // marking the f node as the root node.
+ root = f;
+
+ // add this node to the priority-queue.
+ q.add(f);
+ }
+
+ // print the codes by traversing the tree
+ printCode(root, "");
+ }
+}
+
From 794719c773645a2872ac7c6a3c5a4c17435d1fa4 Mon Sep 17 00:00:00 2001
From: Yang Libin
Date: Fri, 29 Oct 2021 13:19:42 +0800
Subject: [PATCH 0072/1552] Fix formatting in Ciphers package (#2756)
---
Ciphers/AES.java | 1096 +++++++++--------
Ciphers/AESEncryption.java | 152 ++-
Ciphers/AffineCipher.java | 67 +-
Ciphers/Caesar.java | 166 +--
Ciphers/ColumnarTranspositionCipher.java | 326 ++---
Ciphers/HillCipher.java | 277 ++---
Ciphers/RSA.java | 130 +-
...pleSubCipher.java => SimpleSubCipher.java} | 81 +-
Ciphers/SimpleSubstitutionCipher.java | 109 +-
Ciphers/Vigenere.java | 84 +-
Ciphers/affineCipher.java | 83 --
11 files changed, 1230 insertions(+), 1341 deletions(-)
rename Ciphers/{simpleSubCipher.java => SimpleSubCipher.java} (61%)
delete mode 100644 Ciphers/affineCipher.java
diff --git a/Ciphers/AES.java b/Ciphers/AES.java
index d5211d3b1ea0..f67616f87fde 100644
--- a/Ciphers/AES.java
+++ b/Ciphers/AES.java
@@ -9,597 +9,599 @@
*/
public class 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");
- }
+ /**
+ * 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
+ };
- // rotate the first 16 bits to the back
- String rotatingBytes = rBytes.substring(0, 2);
- String fixedBytes = rBytes.substring(2);
+ /**
+ * 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
+ };
- rBytes = new StringBuilder(fixedBytes + rotatingBytes);
+ /**
+ * 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
+ };
- // 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));
+ /**
+ * 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
+ };
- int currentByte = Integer.parseInt(currentByteBits.toString(), 16);
- currentByte = SBOX[currentByte];
+ /**
+ * 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
+ };
- // add the current RCON value to the first byte
- if (i == 0) {
- currentByte = currentByte ^ RCON[rconCounter];
- }
+ /**
+ * 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
+ };
- currentByteBits = new StringBuilder(Integer.toHexString(currentByte));
+ /**
+ * 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
+ };
- // Add zero padding
+ /**
+ * 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
+ };
- while (currentByteBits.length() < 2) {
- currentByteBits.insert(0, '0');
- }
+ /**
+ * 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
+ };
- // replace bytes in original string
- rBytes = new StringBuilder(rBytes.substring(0, i * 2) + currentByteBits + rBytes.substring((i + 1) * 2));
- }
+ /**
+ * Subroutine of the Rijndael key expansion.
+ */
+ public static BigInteger scheduleCore(BigInteger t, int rconCounter) {
+ StringBuilder rBytes = new StringBuilder(t.toString(16));
- // t = new BigInteger(rBytes, 16);
- // return t;
- 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,
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- new BigInteger("0"),
- };
+ // Add zero padding
+ while (rBytes.length() < 8) {
+ rBytes.insert(0, "0");
+ }
- // 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);
+ // 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));
+ }
+
+ // t = new BigInteger(rBytes, 16);
+ // return t;
+ return new BigInteger(rBytes.toString(), 16);
}
- 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');
+
+ /**
+ * 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,
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ new BigInteger("0"),
+ };
+
+ // 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;
}
- // 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);
+ /**
+ * 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;
}
- 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) {
- /**
- * 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]));
- 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');
+ }
- // Append leading 0 for full "8-bit" strings
- while (cellBits.length() < 8) {
- cellBits.insert(0, '0');
- }
+ blockBits.append(cellBits);
+ }
- blockBits.append(cellBits);
+ return new BigInteger(blockBits.toString(), 2);
}
- return new BigInteger(blockBits.toString(), 2);
- }
+ /**
+ * @return ciphertext XOR key
+ */
+ public static BigInteger addRoundKey(BigInteger ciphertext, BigInteger key) {
+ return ciphertext.xor(key);
+ }
- /**
- * @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) {
- /**
- * 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);
- int[] cells = splitBlockIntoCells(ciphertext);
+ for (int i = 0; i < 16; i++) {
+ cells[i] = SBOX[cells[i]];
+ }
- for (int i = 0; i < 16; i++) {
- cells[i] = SBOX[cells[i]];
+ return mergeCellsIntoBlock(cells);
}
- 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);
- /**
- * 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) {
+ for (int i = 0; i < 16; i++) {
+ cells[i] = INVERSE_SBOX[cells[i]];
+ }
- int[] cells = splitBlockIntoCells(ciphertext);
+ return mergeCellsIntoBlock(cells);
+ }
- for (int i = 0; i < 16; i++) {
- cells[i] = INVERSE_SBOX[cells[i]];
+ /**
+ * 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);
}
- 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]];
+ /**
+ * 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);
}
- return mergeCellsIntoBlock(outputCells);
- }
- /**
- * Applies the inverse Rijndael MixColumns for decryption to the input and returns the result.
- */
- public static BigInteger mixColumnsDec(BigInteger ciphertext) {
+ /**
+ * 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];
+ 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]};
+ 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]];
+ 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);
}
- 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]);
+
+ /**
+ * 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);
}
- // 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);
+ /**
+ * 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;
}
- // 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 encrpyt 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));
+ /**
+ * 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);
}
- 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));
+
+ // 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 encrpyt 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 **");
+ }
}
- default -> System.out.println("** End **");
- }
}
- }
}
diff --git a/Ciphers/AESEncryption.java b/Ciphers/AESEncryption.java
index 142aefdd07b4..9857b49d0e36 100644
--- a/Ciphers/AESEncryption.java
+++ b/Ciphers/AESEncryption.java
@@ -1,13 +1,8 @@
package Ciphers;
+import javax.crypto.*;
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;
/**
* This example program shows how AES encryption and decryption can be done in Java. Please note
@@ -16,82 +11,83 @@
*/
public class AESEncryption {
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
- /**
- * 1. Generate a plain text for encryption 2. Get a secret key (printed in hexadecimal form). In
- * actual use this must by 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);
+ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
- 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);
- }
+ /**
+ * 1. Generate a plain text for encryption 2. Get a secret key (printed in hexadecimal form). In
+ * actual use this must by 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);
- /**
- * 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();
- }
+ 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);
+ }
- /**
- * 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
- Cipher aesCipher = Cipher.getInstance("AES");
- aesCipher.init(Cipher.ENCRYPT_MODE, secKey);
- return aesCipher.doFinal(plainText.getBytes());
- }
+ /**
+ * 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();
+ }
- /**
- * 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 {
- // AES defaults to AES/ECB/PKCS5Padding in Java 7
- Cipher aesCipher = Cipher.getInstance("AES");
- aesCipher.init(Cipher.DECRYPT_MODE, secKey);
- byte[] bytePlainText = aesCipher.doFinal(byteCipherText);
- return new String(bytePlainText);
- }
+ /**
+ * 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
+ Cipher aesCipher = Cipher.getInstance("AES");
+ 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 {
+ // AES defaults to AES/ECB/PKCS5Padding in Java 7
+ Cipher aesCipher = Cipher.getInstance("AES");
+ aesCipher.init(Cipher.DECRYPT_MODE, secKey);
+ byte[] bytePlainText = aesCipher.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];
+ /**
+ * 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);
}
- return new String(hexChars);
- }
}
diff --git a/Ciphers/AffineCipher.java b/Ciphers/AffineCipher.java
index 679f742c5d23..d84fb8432ffe 100644
--- a/Ciphers/AffineCipher.java
+++ b/Ciphers/AffineCipher.java
@@ -1,36 +1,23 @@
-//The ‘key’ for the Affine cipher consists of 2 numbers, we’ll call them a and b.
-// The following discussion assumes the use of a 26 character alphabet (m = 26).
-// a should be chosen to be relatively prime to m (i.e. a should have no factors in common with m).
-
package Ciphers;
-import java.util.Scanner;
+class AffineCipher {
-class AffineCipher
-{
- static Scanner in = new Scanner(System.in);
+ // Key values of a and b
+ static int a = 17;
+ static int b = 20;
- static String encryptMessage(char[] msg)
- {
- System.out.println("Enter key value a for encryption : ");
- int a = in.nextInt();
-
- System.out.println("Enter key value b for encryption : ");
- int b = in.nextInt();
-
- /// Initially empty cipher String
+ static String encryptMessage(char[] msg) {
+ /// Cipher Text initially empty
String cipher = "";
- for (int i = 0; i < msg.length; i++)
- {
+ 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 range of ascii alphabet[ 65-90 | A-Z ] */
- if (msg[i] != ' ')
- {
+ if (msg[i] != ' ') {
cipher = cipher
+ (char) ((((a * (msg[i] - 'A')) + b) % 26) + 'A');
- } else // append space character
+ } else // else simply append space character
{
cipher += msg[i];
}
@@ -38,42 +25,30 @@ static String encryptMessage(char[] msg)
return cipher;
}
- static String decryptCipher(String cipher)
- {
- System.out.println("Enter key value a for decryption : ");
- int a = in.nextInt();
-
- System.out.println("Enter key value b for decryption : ");
- int b = in.nextInt();
-
+ static String decryptCipher(String cipher) {
String msg = "";
int a_inv = 0;
int flag = 0;
//Find a^-1 (the multiplicative inverse of a
//in the group of integers modulo m.)
- for (int i = 0; i < 26; i++)
- {
+ for (int i = 0; i < 26; i++) {
flag = (a * i) % 26;
// Check if (a*i)%26 == 1,
- // if so, then i will be the multiplicative inverse of a
- if (flag == 1)
- {
+ // then i will be the multiplicative inverse of a
+ if (flag == 1) {
a_inv = i;
}
}
- for (int i = 0; i < cipher.length(); i++)
- {
+ 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 range of ASCII alphabet[ 65-90 | A-Z ] */
- if (cipher.charAt(i) != ' ')
- {
+ if (cipher.charAt(i) != ' ') {
msg = msg + (char) (((a_inv *
((cipher.charAt(i) + 'A' - b)) % 26)) + 'A');
- }
- else // append space character
+ } else //else simply append space character
{
msg += cipher.charAt(i);
}
@@ -82,17 +57,17 @@ static String decryptCipher(String cipher)
return msg;
}
- // Main method
- public static void main(String[] args)
- {
+ // Driver code
+ public static void main(String[] args) {
String msg = "AFFINE CIPHER";
- // Encrypting message
+ // Calling encryption function
String cipherText = encryptMessage(msg.toCharArray());
System.out.println("Encrypted Message is : " + cipherText);
- // Decrypting message
+ // Calling Decryption function
System.out.println("Decrypted Message is: " + decryptCipher(cipherText));
}
}
+
diff --git a/Ciphers/Caesar.java b/Ciphers/Caesar.java
index 8bd388441fd0..70f6b5266a68 100644
--- a/Ciphers/Caesar.java
+++ b/Ciphers/Caesar.java
@@ -11,105 +11,105 @@
*/
public class Caesar {
- /**
- * Encrypt text by shifting every Latin char by add number shift for ASCII Example : A + 1 -> B
- *
- * @return Encrypted message
- */
- public static String encode(String message, int shift) {
- StringBuilder encoded = new StringBuilder();
+ /**
+ * Encrypt text by shifting every Latin char by add number shift for ASCII Example : A + 1 -> B
+ *
+ * @return Encrypted message
+ */
+ public static String encode(String message, int shift) {
+ StringBuilder encoded = new StringBuilder();
- shift %= 26;
+ shift %= 26;
- final int length = message.length();
- for (int i = 0; i < length; i++) {
+ final int length = message.length();
+ for (int i = 0; i < length; i++) {
- // int current = message.charAt(i); //using char to shift characters because ascii
- // is in-order latin alphabet
- char current = message.charAt(i); // Java law : char + int = char
+ // int current = message.charAt(i); //using char to shift characters because ascii
+ // is in-order latin alphabet
+ char current = message.charAt(i); // Java law : char + int = char
- if (IsCapitalLatinLetter(current)) {
+ if (IsCapitalLatinLetter(current)) {
- current += shift;
- encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters
+ current += shift;
+ encoded.append((char) (current > 'Z' ? current - 26 : current)); // 26 = number of latin letters
- } else if (IsSmallLatinLetter(current)) {
+ } else if (IsSmallLatinLetter(current)) {
- current += shift;
- encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters
+ current += shift;
+ encoded.append((char) (current > 'z' ? current - 26 : current)); // 26 = number of latin letters
- } else {
- encoded.append(current);
- }
+ } else {
+ encoded.append(current);
+ }
+ }
+ return encoded.toString();
}
- return encoded.toString();
- }
- /**
- * Decrypt message by shifting back every Latin char to previous the ASCII Example : B - 1 -> A
- *
- * @return message
- */
- public static String decode(String encryptedMessage, int shift) {
- StringBuilder decoded = new StringBuilder();
+ /**
+ * Decrypt message by shifting back every Latin char to previous the ASCII Example : B - 1 -> A
+ *
+ * @return message
+ */
+ public static String decode(String encryptedMessage, int shift) {
+ StringBuilder decoded = new StringBuilder();
- shift %= 26;
+ shift %= 26;
- final int length = encryptedMessage.length();
- for (int i = 0; i < length; i++) {
- char current = encryptedMessage.charAt(i);
- if (IsCapitalLatinLetter(current)) {
+ final int length = encryptedMessage.length();
+ for (int i = 0; i < length; i++) {
+ char current = encryptedMessage.charAt(i);
+ if (IsCapitalLatinLetter(current)) {
- current -= shift;
- decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters
+ current -= shift;
+ decoded.append((char) (current < 'A' ? current + 26 : current)); // 26 = number of latin letters
- } else if (IsSmallLatinLetter(current)) {
+ } else if (IsSmallLatinLetter(current)) {
- current -= shift;
- decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters
+ current -= shift;
+ decoded.append((char) (current < 'a' ? current + 26 : current)); // 26 = number of latin letters
- } else {
- decoded.append(current);
- }
+ } else {
+ decoded.append(current);
+ }
+ }
+ return decoded.toString();
}
- return decoded.toString();
- }
-
- /**
- * @return true if character is capital Latin letter or false for others
- */
- private static boolean IsCapitalLatinLetter(char c) {
- return c >= 'A' && c <= 'Z';
- }
-
- /**
- * @return true if character is small Latin letter or false for others
- */
- private static boolean IsSmallLatinLetter(char c) {
- return c >= 'a' && c <= 'z';
- }
-
- public static void main(String[] args) {
- Scanner input = new Scanner(System.in);
- System.out.println("Please enter the message (Latin Alphabet)");
- String message = input.nextLine();
- System.out.println(message);
- System.out.println("Please enter the shift number");
- int shift = input.nextInt() % 26;
- System.out.println("(E)ncode or (D)ecode ?");
- char choice = input.next().charAt(0);
- switch (choice) {
- case 'E':
- case 'e':
- System.out.println(
- "ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle
- break;
- case 'D':
- case 'd':
- System.out.println("DECODED MESSAGE IS \n" + decode(message, shift));
- default:
- System.out.println("default case");
+
+ /**
+ * @return true if character is capital Latin letter or false for others
+ */
+ private static boolean IsCapitalLatinLetter(char c) {
+ return c >= 'A' && c <= 'Z';
+ }
+
+ /**
+ * @return true if character is small Latin letter or false for others
+ */
+ private static boolean IsSmallLatinLetter(char c) {
+ return c >= 'a' && c <= 'z';
+ }
+
+ public static void main(String[] args) {
+ Scanner input = new Scanner(System.in);
+ System.out.println("Please enter the message (Latin Alphabet)");
+ String message = input.nextLine();
+ System.out.println(message);
+ System.out.println("Please enter the shift number");
+ int shift = input.nextInt() % 26;
+ System.out.println("(E)ncode or (D)ecode ?");
+ char choice = input.next().charAt(0);
+ switch (choice) {
+ case 'E':
+ case 'e':
+ System.out.println(
+ "ENCODED MESSAGE IS \n" + encode(message, shift)); // send our function to handle
+ break;
+ case 'D':
+ case 'd':
+ System.out.println("DECODED MESSAGE IS \n" + decode(message, shift));
+ default:
+ System.out.println("default case");
+ }
+ input.close();
}
- input.close();
- }
}
diff --git a/Ciphers/ColumnarTranspositionCipher.java b/Ciphers/ColumnarTranspositionCipher.java
index 272ebe9255ce..ab5df61ea336 100644
--- a/Ciphers/ColumnarTranspositionCipher.java
+++ b/Ciphers/ColumnarTranspositionCipher.java
@@ -9,191 +9,193 @@
*/
public class ColumnarTranspositionCipher {
- private static String keyword;
- private static Object[][] table;
- private static String abecedarium;
- public static final String ABECEDARIUM =
- "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
- private static final String ENCRYPTION_FIELD = "≈";
- private static final char ENCRYPTION_FIELD_CHAR = '≈';
+ private static String keyword;
+ private static Object[][] table;
+ private static String abecedarium;
+ public static final String ABECEDARIUM =
+ "abcdefghijklmnopqrstuvwxyzABCDEFG" + "HIJKLMNOPQRSTUVWXYZ0123456789,.;:-@";
+ private static final String ENCRYPTION_FIELD = "≈";
+ private static final char ENCRYPTION_FIELD_CHAR = '≈';
- /**
- * Encrypts a certain String with the Columnar Transposition Cipher Rule
- *
- * @param word Word being encrypted
- * @param keyword String with keyword being used
- * @return a String with the word encrypted by the Columnar Transposition Cipher Rule
- */
- public static String encrpyter(String word, String keyword) {
- ColumnarTranspositionCipher.keyword = keyword;
- abecedariumBuilder(500);
- table = tableBuilder(word);
- Object[][] sortedTable = sortTable(table);
- StringBuilder wordEncrypted = new StringBuilder();
- for (int i = 0; i < sortedTable[i].length; i++) {
- for (int j = 1; j < sortedTable.length; j++) {
- wordEncrypted.append(sortedTable[j][i]);
- }
+ /**
+ * Encrypts a certain String with the Columnar Transposition Cipher Rule
+ *
+ * @param word Word being encrypted
+ * @param keyword String with keyword being used
+ * @return a String with the word encrypted by the Columnar Transposition Cipher Rule
+ */
+ public static String encrpyter(String word, String keyword) {
+ ColumnarTranspositionCipher.keyword = keyword;
+ abecedariumBuilder(500);
+ table = tableBuilder(word);
+ Object[][] sortedTable = sortTable(table);
+ StringBuilder wordEncrypted = new StringBuilder();
+ for (int i = 0; i < sortedTable[i].length; i++) {
+ for (int j = 1; j < sortedTable.length; j++) {
+ wordEncrypted.append(sortedTable[j][i]);
+ }
+ }
+ return wordEncrypted.toString();
}
- return wordEncrypted.toString();
- }
- /**
- * Encrypts a certain String with the Columnar Transposition Cipher Rule
- *
- * @param word Word being encrypted
- * @param keyword String with keyword being used
- * @param abecedarium String with the abecedarium being used. null for default one
- * @return a String with the word encrypted by the Columnar Transposition Cipher Rule
- */
- public static String encrpyter(String word, String keyword, String abecedarium) {
- ColumnarTranspositionCipher.keyword = keyword;
- ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
- table = tableBuilder(word);
- Object[][] sortedTable = sortTable(table);
- StringBuilder wordEncrypted = new StringBuilder();
- for (int i = 0; i < sortedTable[0].length; i++) {
- for (int j = 1; j < sortedTable.length; j++) {
- wordEncrypted.append(sortedTable[j][i]);
- }
+ /**
+ * Encrypts a certain String with the Columnar Transposition Cipher Rule
+ *
+ * @param word Word being encrypted
+ * @param keyword String with keyword being used
+ * @param abecedarium String with the abecedarium being used. null for default one
+ * @return a String with the word encrypted by the Columnar Transposition Cipher Rule
+ */
+ public static String encrpyter(String word, String keyword, String abecedarium) {
+ ColumnarTranspositionCipher.keyword = keyword;
+ ColumnarTranspositionCipher.abecedarium = Objects.requireNonNullElse(abecedarium, ABECEDARIUM);
+ table = tableBuilder(word);
+ Object[][] sortedTable = sortTable(table);
+ StringBuilder wordEncrypted = new StringBuilder();
+ for (int i = 0; i < sortedTable[0].length; i++) {
+ for (int j = 1; j < sortedTable.length; j++) {
+ wordEncrypted.append(sortedTable[j][i]);
+ }
+ }
+ return wordEncrypted.toString();
}
- return wordEncrypted.toString();
- }
- /**
- * Decrypts a certain encrypted String with the Columnar Transposition Cipher Rule
- *
- * @return a String decrypted with the word encrypted by the Columnar Transposition Cipher Rule
- */
- public static String decrypter() {
- StringBuilder wordDecrypted = new StringBuilder();
- for (int i = 1; i < table.length; i++) {
- for (Object item : table[i]) {
- wordDecrypted.append(item);
- }
+ /**
+ * Decrypts a certain encrypted String with the Columnar Transposition Cipher Rule
+ *
+ * @return a String decrypted with the word encrypted by the Columnar Transposition Cipher Rule
+ */
+ public static String decrypter() {
+ StringBuilder wordDecrypted = new StringBuilder();
+ for (int i = 1; i < table.length; i++) {
+ for (Object item : table[i]) {
+ wordDecrypted.append(item);
+ }
+ }
+ return wordDecrypted.toString().replaceAll(ENCRYPTION_FIELD, "");
}
- return wordDecrypted.toString().replaceAll(ENCRYPTION_FIELD, "");
- }
- /**
- * Builds a table with the word to be encrypted in rows by the Columnar Transposition Cipher Rule
- *
- * @return An Object[][] with the word to be encrypted filled in rows and columns
- */
- private static Object[][] tableBuilder(String word) {
- Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()];
- char[] wordInChards = word.toCharArray();
- // Fils in the respective numbers
- table[0] = findElements();
- int charElement = 0;
- for (int i = 1; i < table.length; i++) {
- for (int j = 0; j < table[i].length; j++) {
- if (charElement < wordInChards.length) {
- table[i][j] = wordInChards[charElement];
- charElement++;
- } else {
- table[i][j] = ENCRYPTION_FIELD_CHAR;
+ /**
+ * Builds a table with the word to be encrypted in rows by the Columnar Transposition Cipher Rule
+ *
+ * @return An Object[][] with the word to be encrypted filled in rows and columns
+ */
+ private static Object[][] tableBuilder(String word) {
+ Object[][] table = new Object[numberOfRows(word) + 1][keyword.length()];
+ char[] wordInChards = word.toCharArray();
+ // Fils in the respective numbers
+ table[0] = findElements();
+ int charElement = 0;
+ for (int i = 1; i < table.length; i++) {
+ for (int j = 0; j < table[i].length; j++) {
+ if (charElement < wordInChards.length) {
+ table[i][j] = wordInChards[charElement];
+ charElement++;
+ } else {
+ table[i][j] = ENCRYPTION_FIELD_CHAR;
+ }
+ }
}
- }
+ return table;
}
- return table;
- }
- /**
- * Determines the number of rows the table should have regarding the Columnar Transposition Cipher
- * Rule
- *
- * @return an int with the number of rows that the table should have in order to respect the
- * Columnar Transposition Cipher Rule.
- */
- private static int numberOfRows(String word) {
- if (word.length() / keyword.length() > word.length() / keyword.length()) {
- return (word.length() / keyword.length()) + 1;
- } else {
- return word.length() / keyword.length();
+ /**
+ * Determines the number of rows the table should have regarding the Columnar Transposition Cipher
+ * Rule
+ *
+ * @return an int with the number of rows that the table should have in order to respect the
+ * Columnar Transposition Cipher Rule.
+ */
+ private static int numberOfRows(String word) {
+ if (word.length() / keyword.length() > word.length() / keyword.length()) {
+ return (word.length() / keyword.length()) + 1;
+ } else {
+ return word.length() / keyword.length();
+ }
}
- }
- /** @return charValues */
- private static Object[] findElements() {
- Object[] charValues = new Object[keyword.length()];
- for (int i = 0; i < charValues.length; i++) {
- int charValueIndex = abecedarium.indexOf(keyword.charAt(i));
- charValues[i] = charValueIndex > -1 ? charValueIndex : null;
+ /**
+ * @return charValues
+ */
+ private static Object[] findElements() {
+ Object[] charValues = new Object[keyword.length()];
+ for (int i = 0; i < charValues.length; i++) {
+ int charValueIndex = abecedarium.indexOf(keyword.charAt(i));
+ charValues[i] = charValueIndex > -1 ? charValueIndex : null;
+ }
+ return charValues;
}
- return charValues;
- }
- /**
- * @return tableSorted
- */
- private static Object[][] sortTable(Object[][] table) {
- Object[][] tableSorted = new Object[table.length][table[0].length];
- for (int i = 0; i < tableSorted.length; i++) {
- System.arraycopy(table[i], 0, tableSorted[i], 0, tableSorted[i].length);
- }
- for (int i = 0; i < tableSorted[0].length; i++) {
- for (int j = i + 1; j < tableSorted[0].length; j++) {
- if ((int) tableSorted[0][i] > (int) table[0][j]) {
- Object[] column = getColumn(tableSorted, tableSorted.length, i);
- switchColumns(tableSorted, j, i, column);
+ /**
+ * @return tableSorted
+ */
+ private static Object[][] sortTable(Object[][] table) {
+ Object[][] tableSorted = new Object[table.length][table[0].length];
+ for (int i = 0; i < tableSorted.length; i++) {
+ System.arraycopy(table[i], 0, tableSorted[i], 0, tableSorted[i].length);
+ }
+ for (int i = 0; i < tableSorted[0].length; i++) {
+ for (int j = i + 1; j < tableSorted[0].length; j++) {
+ if ((int) tableSorted[0][i] > (int) table[0][j]) {
+ Object[] column = getColumn(tableSorted, tableSorted.length, i);
+ switchColumns(tableSorted, j, i, column);
+ }
+ }
}
- }
+ return tableSorted;
}
- return tableSorted;
- }
- /**
- * @return columnArray
- */
- private static Object[] getColumn(Object[][] table, int rows, int column) {
- Object[] columnArray = new Object[rows];
- for (int i = 0; i < rows; i++) {
- columnArray[i] = table[i][column];
+ /**
+ * @return columnArray
+ */
+ private static Object[] getColumn(Object[][] table, int rows, int column) {
+ Object[] columnArray = new Object[rows];
+ for (int i = 0; i < rows; i++) {
+ columnArray[i] = table[i][column];
+ }
+ return columnArray;
}
- return columnArray;
- }
- private static void switchColumns(
- Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
- for (int i = 0; i < table.length; i++) {
- table[i][secondColumnIndex] = table[i][firstColumnIndex];
- table[i][firstColumnIndex] = columnToSwitch[i];
+ private static void switchColumns(
+ Object[][] table, int firstColumnIndex, int secondColumnIndex, Object[] columnToSwitch) {
+ for (int i = 0; i < table.length; i++) {
+ table[i][secondColumnIndex] = table[i][firstColumnIndex];
+ table[i][firstColumnIndex] = columnToSwitch[i];
+ }
}
- }
- /**
- * Creates an abecedarium with a specified ascii inded
- *
- * @param value Number of characters being used based on the ASCII Table
- */
- private static void abecedariumBuilder(int value) {
- StringBuilder t = new StringBuilder();
- for (int i = 0; i < value; i++) {
- t.append((char) i);
+ /**
+ * Creates an abecedarium with a specified ascii inded
+ *
+ * @param value Number of characters being used based on the ASCII Table
+ */
+ private static void abecedariumBuilder(int value) {
+ StringBuilder t = new StringBuilder();
+ for (int i = 0; i < value; i++) {
+ t.append((char) i);
+ }
+ abecedarium = t.toString();
}
- abecedarium = t.toString();
- }
- private static void showTable() {
- for (Object[] table1 : table) {
- for (Object item : table1) {
- System.out.print(item + " ");
- }
- System.out.println();
+ private static void showTable() {
+ for (Object[] table1 : table) {
+ for (Object item : table1) {
+ System.out.print(item + " ");
+ }
+ System.out.println();
+ }
}
- }
- public static void main(String[] args) {
- String keywordForExample = "asd215";
- String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher";
- System.out.println("### Example of Columnar Transposition Cipher ###\n");
- System.out.println("Word being encryped ->>> " + wordBeingEncrypted);
- System.out.println(
- "Word encrypted ->>> "
- + ColumnarTranspositionCipher.encrpyter(wordBeingEncrypted, keywordForExample));
- System.out.println("Word decryped ->>> " + ColumnarTranspositionCipher.decrypter());
- System.out.println("\n### Encrypted Table ###");
- showTable();
- }
+ public static void main(String[] args) {
+ String keywordForExample = "asd215";
+ String wordBeingEncrypted = "This is a test of the Columnar Transposition Cipher";
+ System.out.println("### Example of Columnar Transposition Cipher ###\n");
+ System.out.println("Word being encryped ->>> " + 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/HillCipher.java b/Ciphers/HillCipher.java
index 0a3b50308d21..2150576ffc00 100644
--- a/Ciphers/HillCipher.java
+++ b/Ciphers/HillCipher.java
@@ -1,172 +1,165 @@
package Ciphers;
-import java.util.*;
+import java.util.Scanner;
/*
-* Java Implementation of Hill Cipher
-* Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number belonging to the set Z26 where A=0 , B=1, ..... Z=25.
-* To encrypt a message, each block of n letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against modulus 26.
-* To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption.
-* The cipher key and plaintext/ciphertext are user inputs.
-* @author Ojasva Jain
-*/
+ * Java Implementation of Hill Cipher
+ * Hill cipher is a polyalphabetic substitution cipher. Each letter is represented by a number belonging to the set Z26 where A=0 , B=1, ..... Z=25.
+ * To encrypt a message, each block of n letters (since matrix size is n x n) is multiplied by an invertible n × n matrix, against modulus 26.
+ * To decrypt the message, each block is multiplied by the inverse of the matrix used for encryption.
+ * The cipher key and plaintext/ciphertext are user inputs.
+ * @author Ojasva Jain
+ */
-public class HillCipher{
-static Scanner in = new Scanner (System.in);
+public class HillCipher {
+ static Scanner in = new Scanner(System.in);
-/* Following function encrypts the message
-*/
-static void encrypt(String message)
-{
- message = message.toUpperCase();
- // Get key matrix
- System.out.println("Enter key matrix size");
- int n = in.nextInt();
- System.out.println("Enter Key/encryptionKey matrix ");
- int keyMatrix[][] = new int [n][n];
- for(int i=0;i