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.

Applications

  • Often incorporated as part of more complex schemes, such as the Vigenère cipher

Complexity

  • Time: best O(N * #ofRotations), worst O(N * #ofRotations * alphabetSize)
  • Space: best O(1), worst O(alphabetSize)

References

Implementations

  • 1
    
    # TODO: Implement in Python
    
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    
    const string = 'hello! how are you doing?';
    const rotation = 5;
    const alphabet = 'abcdefghijklmnopqrstuvwxyz';
    // create a map of char -> position to improve run time
    // otherwise we would have to search the alphabet each
    // time to find the character position
    const alphabetMap = alphabet.split('').reduce((map, curr, idx) => {
      map[curr] = idx;
      return map;
    }, {});
    
    function getPosUp(pos) {
      return (pos === alphabet.length - 1) ? 0 : pos + 1;
    }
    
    function getPosDown(pos) {
      return (pos === 0) ? alphabet.length - 1 : pos - 1;
    }
    
    function getNextChar(currChar, direction) {
      const pos = alphabetMap[currChar];
      const nextPos = direction === 'up' ? getPosUp(pos) : getPosDown(pos);
      const nextChar = alphabet.charAt(nextPos);
    
      console.log(`${currChar} -> ${nextChar}`);
      
      return nextChar;
    }
    
    function cipher(str, rotation, direction, cipherTracer) {
      if (!str) return '';
    
      for (let i = 0; i < str.length; i++) {
    
        let currChar = str.charAt(i);
        if (typeof alphabetMap[currChar] === 'number') { // don't encrpt/decrypt characters not in  alphabetMap
          let r = rotation;
    
          console.log(`Rotating ${currChar} ${direction} ${rotation} times`);
    
          // perform given amount of rotations in the given direction
          while (r-- > 0) {
            currChar = getNextChar(currChar, direction);
            
          }
        } else {
          
          console.log('Ignore this character');
          
        }
        str = str.substring(0, i) + currChar + str.substring(i + 1);
        
        console.log(`Current result: ${str}`);
        
      }
    
      return str;
    }
    
    function encrypt(str, rotation) {
      
      console.log(`Encrypting: ${str}`);
      
      return cipher(str, rotation, 'up', encryptTracer);
    }
    
    function decrypt(str, rotation) {
      
      console.log(`Decrypting: ${str}`);
      
      return cipher(str, rotation, 'down', decryptTracer);
    }
    
    const encrypted = encrypt(string, rotation);
    
    console.log(`Encrypted result: ${encrypted}`);
    
    decryptTracer.set(encrypted);
    const decrypted = decrypt(encrypted, rotation);
    
    console.log(`Decrypted result: ${decrypted}`);