Search code examples
pythonencryptioncyclepython-itertoolsvigenere

itertools cycle in vigenere cipher causing problems with spaces python


In my code for vigenere cipher I use cycle from itertools to cycle through the key word. This works great until I use spaces in the message as it encrypts the space therefore making the encryption wrong. Here is the code.

    message = input('enter message: ')
    keyword = input('enter keyword: ')
    def chr_to_int(char):
        return 0 if char == 'z' else ord(char)-96
    def int_to_chr(integer):
        return 'z' if integer == 0 else chr(integer+96)
    def add_chars(a, b):
        return int_to_chr(( chr_to_int(a) + chr_to_int(b)) % 26 )
    def vigenere(message, keyword):
        keystream = cycle(keyword)
        new = ''
        for msg, key in zip(message, keystream):
            if msg == ' ':
                new += ' '
            else:
                new += add_chars(msg, key)
        return new

    new = vigenere(message, keyword)
    print('your encrypted message is: ',new)

I think a solution to this problem would be to cycle through the space the same length of the message so it will carry on to the next letter as if the space wasn't there. I do not know how to go about how to do this .

example:

message: vignere cipher keyword: qwerty

encrypted mesasge (what it should be): mflahdib hajgvo


Solution

  • since cycle returns an iterable, you could instead use next instead of zip so that it only calls for the next char when asked:

    >>> def vigenere(message, keyword):
            keystream = cycle(keyword)
            new = ''
            for msg in message:
                if msg == ' ':
                    new += ' '
                else:
                    new += add_chars(msg, next(keystream))
            return new
    
    >>> new = vigenere('computing is fun', 'gcse')
    >>> new
    'jrfubwbsn ll kbq'
    

    EDIT: per OP request, uses zip and offset variable

    >>> def vigenere(message, keyword):
            keystream = cycle(keyword)
            new = ''
            offset = 0
            for msg, key in zip(message,keystream):
                if msg == ' ':
                    new += ' '
                    offset += 1
                else:
                    new += add_chars(msg, keyword[keyword.index(key)-offset])
            return new
    >>> new = vigenere('computing is fun', 'gcse')
    >>> new
    'jrfubwbsn ll kbq'