Skip to content

Commit 0024241

Browse files
committedAug 8, 2020
Refactor a Caesar Cipher algorithm.
1 parent bd7475e commit 0024241

File tree

7 files changed

+129
-72
lines changed

7 files changed

+129
-72
lines changed
 

‎README.md

+1
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ a set of rules that precisely define a sequence of operations.
135135
* `A` [Travelling Salesman Problem](src/algorithms/graph/travelling-salesman) - shortest possible route that visits each city and returns to the origin city
136136
* **Cryptography**
137137
* `B` [Polynomial Hash](src/algorithms/cryptography/polynomial-hash) - rolling hash function based on polynomial
138+
* `B` [Caesar Cipher](src/algorithms/cryptography/caesar-cipher) - simple substitution cipher
138139
* **Machine Learning**
139140
* `B` [NanoNeuron](https://github.com/trekhleb/nano-neuron) - 7 simple JS functions that illustrate how machines can actually learn (forward/backward propagation)
140141
* **Uncategorized**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Caesar Cipher Algorithm
2+
3+
In cryptography, a **Caesar cipher**, also known as **Caesar's cipher**, the **shift cipher**, **Caesar's code** or **Caesar shift**, is one of the simplest and most widely known encryption techniques. It is a type of substitution cipher in which each letter in the plaintext is replaced by a letter some fixed number of positions down the alphabet. For example, with a left shift of `3`, `D` would be replaced by `A`, `E` would become `B`, and so on. The method is named after Julius Caesar, who used it in his private correspondence.
4+
5+
![Caesar Cipher Algorithm](https://upload.wikimedia.org/wikipedia/commons/4/4a/Caesar_cipher_left_shift_of_3.svg)
6+
7+
## Example
8+
9+
The transformation can be represented by aligning two alphabets; the cipher alphabet is the plain alphabet rotated left or right by some number of positions. For instance, here is a Caesar cipher using a left rotation of three places, equivalent to a right shift of 23 (the shift parameter is used as the key):
10+
11+
```text
12+
Plain: ABCDEFGHIJKLMNOPQRSTUVWXYZ
13+
Cipher: XYZABCDEFGHIJKLMNOPQRSTUVW
14+
```
15+
16+
When encrypting, a person looks up each letter of the message in the "plain" line and writes down the corresponding letter in the "cipher" line.
17+
18+
```text
19+
Plaintext: THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG
20+
Ciphertext: QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD
21+
```
22+
23+
## Complexity
24+
25+
- Time: `O(|n|)`
26+
- Space: `O(|n|)`
27+
28+
## References
29+
30+
- [Caesar cipher on Wikipedia](https://en.wikipedia.org/wiki/Caesar_cipher)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { caesarCipherEncrypt, caesarCipherDecrypt } from '../caesarCipher';
2+
3+
describe('caesarCipher', () => {
4+
it('should not change a string with zero shift', () => {
5+
expect(caesarCipherEncrypt('abcd', 0)).toBe('abcd');
6+
expect(caesarCipherDecrypt('abcd', 0)).toBe('abcd');
7+
});
8+
9+
it('should cipher a string with different shifts', () => {
10+
expect(caesarCipherEncrypt('abcde', 3)).toBe('defgh');
11+
expect(caesarCipherDecrypt('defgh', 3)).toBe('abcde');
12+
13+
expect(caesarCipherEncrypt('abcde', 1)).toBe('bcdef');
14+
expect(caesarCipherDecrypt('bcdef', 1)).toBe('abcde');
15+
16+
expect(caesarCipherEncrypt('xyz', 1)).toBe('yza');
17+
expect(caesarCipherDecrypt('yza', 1)).toBe('xyz');
18+
});
19+
20+
it('should be case insensitive', () => {
21+
expect(caesarCipherEncrypt('ABCDE', 3)).toBe('defgh');
22+
});
23+
24+
it('should correctly handle an empty strings', () => {
25+
expect(caesarCipherEncrypt('', 3)).toBe('');
26+
});
27+
28+
it('should not cipher unknown chars', () => {
29+
expect(caesarCipherEncrypt('ab2cde', 3)).toBe('de2fgh');
30+
expect(caesarCipherDecrypt('de2fgh', 3)).toBe('ab2cde');
31+
});
32+
33+
it('should encrypt and decrypt full phrases', () => {
34+
expect(caesarCipherEncrypt('THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG', 23))
35+
.toBe('qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald');
36+
37+
expect(caesarCipherDecrypt('qeb nrfzh yoltk clu grjmp lsbo qeb ixwv ald', 23))
38+
.toBe('the quick brown fox jumps over the lazy dog');
39+
});
40+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Create alphabet array: ['a', 'b', 'c', ..., 'z'].
2+
const englishAlphabet = 'abcdefghijklmnopqrstuvwxyz'.split('');
3+
4+
/**
5+
* Generates a cipher map out of the alphabet.
6+
* Example with a shift 3: {'a': 'd', 'b': 'e', 'c': 'f', ...}
7+
*
8+
* @param {string[]} alphabet - i.e. ['a', 'b', 'c', ... , 'z']
9+
* @param {number} shift - i.e. 3
10+
* @return {Object} - i.e. {'a': 'd', 'b': 'e', 'c': 'f', ..., 'z': 'c'}
11+
*/
12+
const getCipherMap = (alphabet, shift) => {
13+
return alphabet
14+
.reduce((charsMap, currentChar, charIndex) => {
15+
const charsMapClone = { ...charsMap };
16+
// Making the shift to be cyclic (i.e. with a shift of 1 - 'z' would be mapped to 'a').
17+
let encryptedCharIndex = (charIndex + shift) % alphabet.length;
18+
// Support negative shifts for creating a map for decryption
19+
// (i.e. with shift -1 - 'a' would be mapped to 'z').
20+
if (encryptedCharIndex < 0) {
21+
encryptedCharIndex += alphabet.length;
22+
}
23+
charsMapClone[currentChar] = alphabet[encryptedCharIndex];
24+
return charsMapClone;
25+
}, {});
26+
};
27+
28+
/**
29+
* @param {string} str
30+
* @param {number} shift
31+
* @param {string[]} alphabet
32+
* @return {string}
33+
*/
34+
export const caesarCipherEncrypt = (str, shift, alphabet = englishAlphabet) => {
35+
// Create a cipher map:
36+
const cipherMap = getCipherMap(alphabet, shift);
37+
return str
38+
.toLowerCase()
39+
.split('')
40+
.map((char) => cipherMap[char] || char)
41+
.join('');
42+
};
43+
44+
/**
45+
* @param {string} str
46+
* @param {number} shift
47+
* @param {string[]} alphabet
48+
* @return {string}
49+
*/
50+
export const caesarCipherDecrypt = (str, shift, alphabet = englishAlphabet) => {
51+
// Create a cipher map:
52+
const cipherMap = getCipherMap(alphabet, -shift);
53+
return str
54+
.toLowerCase()
55+
.split('')
56+
.map((char) => cipherMap[char] || char)
57+
.join('');
58+
};

‎src/algorithms/string/caeserCipher/README.md

-15
This file was deleted.

‎src/algorithms/string/caeserCipher/__test__/caeserCipher.test.js

-27
This file was deleted.

‎src/algorithms/string/caeserCipher/caeserCipher.js

-30
This file was deleted.

0 commit comments

Comments
 (0)
Please sign in to comment.