pythonencryptioncryptographycaesar-cipher

New character depending on old character in Caesar Cipher


I have written a Caesar cipher with 2 parameters m and n,with characters to be shifted as follows:

  1. The first character (char1) is shifted (n+m) places.
  2. Then, the second character (char2) shifted n+(pos_char1) places, where pos_char1 is the index of char1 in the alphabet (a-z); char3 is shifted n+(pos_char2) places, where pos_char2 is the index of char2 ... and so on.
  3. The cipher works only on lowercase letters, and all other characters are ignored.

It works fine as expected for encoding but not for decoding.

Below is my code.

def encode_cipher(n, m,message):
    result = ""
    p = m  # Initialize p with the additional step shift 'm'

    for char in message:
        if char.islower():
        # Determine the shift value for the current lowercase character
            shift = n + p
        # Adjust the shift to keep it within the range [0, 25]
            shift = shift % 26

            new_char = chr(((ord(char) - ord('a') + shift) % 26) + ord('a'))
            result += new_char

        # Update the value of p for the next character
            p = ((ord(new_char) - ord('a')) % 26)
        else:
            # If the character is not a lowercase letter, leave it unchanged
            result += char

    return result

# Example usage for encoding
message = "aaaaaa"
n = 2
m = 2

encode_cipher( n, m,message)

#output is: "egikmo", as expected.

Now to decrypt, I have written the following:

def decode_cipher(n, m,message):
    result = ""
    p = m  # Initialize p 

    for char in message:
        if char.islower():
            shift = n + p
            shift = shift % 26

            new_char = chr(((ord(char) - ord('a') - shift) % 26) + ord('a'))
            result += new_char

        # Update the value of p for the next character
            p = ((ord(new_char) - ord('a')) % 26)
        else:
            result += char

    return result

# Example
message = "egikmo" # Using output from encode function above. 
n = 2
m = 2

decode_cipher( n, m,message)

The output is not "aaaaaa" i.e. the original message before encoding. So obviously subtracting the shift is not working and I wonder what I am missing.


Solution

  • ==========================
    EDIT:
    After the comment. To fix you decode function according to your explanation in the comment, you'll simply need to change this line:

    p = ((ord(new_char) - ord('a')) % 26)
    

    with this:

    p = ((ord(char) - ord('a')) % 26)
    

    The difference is that you were using the index of the decoded character, instead of the character that weren't decoded.

    ==========================

    For start, you meant to encrypt the first character with a shift of n + m, and you did that correctly. For all the other characters, you wanted to encrypt with a shift of n + the index of the former character, and that you failed to do.

    I'll explain, the mistake is small, and located in this line:

    p = ((ord(new_char) - ord('a')) % 26)
    

    Instead of that, you should have just assigned the index of the current character. To do that you need to get the index of the character along with the character, and one way to do that is iterate over a range in the length of the message, and obtain the character using the square brackets [index].

    After updating the encode function it would look like this:

    def encode_cipher(n, m,message):
    result = ""
    p = m
    
    for i in range(len(message)):
        char = message[i]
        if char.islower():
            shift = n + p
            shift = shift % 26
    
            new_char = chr(((ord(char) - ord('a') + shift) % 26) + ord('a'))
            result += new_char
    
            p = i
        else:
            result += char
    
        return result
    

    Just to finish this answer, let's simply update the decode function also:

    def decode_cipher(n, m,message):
    result = ""
    p = m
    
    for i in range(len(message)):
        char = message[i]
        if char.islower():
            shift = n + p
            shift = shift % 26
    
            new_char = chr(((ord(char) - ord('a') - shift) % 26) + ord('a'))
            result += new_char
    
            p = i
        else:
            result += char
    
        return result
    

    Another thing: Because the difference between the functions is so minor, we can use the same function with a slight adjustment, it would look like this:

    def my_cipher(n, m, message, decode=False):
    result = ""
    p = m
    for i in range(len(message)):
        char = message[i]
        if char.islower():
            shift = n + p
            shift = shift % 26
            
            if not decode:
                new_char = chr(((ord(char) - ord('a') + shift) % 26) + ord('a'))
            else:
                new_char = chr(((ord(char) - ord('a') - shift) % 26) + ord('a'))
            
            result += new_char
            p = i
        else:
            result += char
    
        return result
    

    Best regards, and good luck with your project!