Skip to content

Commit 0024241

Browse files
committed
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

Lines changed: 1 addition & 0 deletions
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**
Lines changed: 30 additions & 0 deletions
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)
Lines changed: 40 additions & 0 deletions
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+
});
Lines changed: 58 additions & 0 deletions
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

Lines changed: 0 additions & 15 deletions
This file was deleted.

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

Lines changed: 0 additions & 27 deletions
This file was deleted.

src/algorithms/string/caeserCipher/caeserCipher.js

Lines changed: 0 additions & 30 deletions
This file was deleted.

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy