Search code examples
pythonvigenere

For Kasiski Test,How to implement 26x26 table in Python


Here is the table http://en.wikipedia.org/wiki/File:Vigen%C3%A8re_square_shading.svg

How can I implement this table in Python? What is the way(s) for this?

And any clue about how can I check for example Row: L & Column G becomes R welcome.


Solution

  • I like to use the standard library where possible to avoid rolling my own code and inadvertently leaving things out (like accidentally misplacing or forgetting a letter.)

    import string
    import collections
    
    def vigsquare(printable=False):
        '''
        Returns a string like a vigenere square,
        printable joins each row with a newline so it's literally square
        printable=False (defaul) joins without newlines for easier 
        searching by row and column index
        '''
        alpha = string.ascii_uppercase
        rotater = collections.deque(alpha)
        vigsquare_list = []
        for i in xrange(26):
            vigsquare_list.append(''.join(rotater))
            rotater.rotate(-1)
        if printable:
            return '\n'.join(vigsquare_list) 
        else:
            return ''.join(vigsquare_list)
    

    and

    def vigenere(row, column):
        ''' 
        Return a character from a vigenere square by 
        row and column letter.
        vigenere('L', 'G') returns 'R'
        '''
        alpha = string.ascii_uppercase
        rowindex = alpha.find(row)
        columnindex = alpha.find(column)
        return vigsquare()[rowindex*26 + columnindex]
    
    print vigsquare(printable=True)
    vigenere('L', 'G')
    

    gives you:

    ABCDEFGHIJKLMNOPQRSTUVWXYZ
    BCDEFGHIJKLMNOPQRSTUVWXYZA
    CDEFGHIJKLMNOPQRSTUVWXYZAB
    DEFGHIJKLMNOPQRSTUVWXYZABC
    EFGHIJKLMNOPQRSTUVWXYZABCD
    FGHIJKLMNOPQRSTUVWXYZABCDE
    GHIJKLMNOPQRSTUVWXYZABCDEF
    HIJKLMNOPQRSTUVWXYZABCDEFG
    IJKLMNOPQRSTUVWXYZABCDEFGH
    JKLMNOPQRSTUVWXYZABCDEFGHI
    KLMNOPQRSTUVWXYZABCDEFGHIJ
    LMNOPQRSTUVWXYZABCDEFGHIJK
    MNOPQRSTUVWXYZABCDEFGHIJKL
    NOPQRSTUVWXYZABCDEFGHIJKLM
    OPQRSTUVWXYZABCDEFGHIJKLMN
    PQRSTUVWXYZABCDEFGHIJKLMNO
    QRSTUVWXYZABCDEFGHIJKLMNOP
    RSTUVWXYZABCDEFGHIJKLMNOPQ
    STUVWXYZABCDEFGHIJKLMNOPQR
    TUVWXYZABCDEFGHIJKLMNOPQRS
    UVWXYZABCDEFGHIJKLMNOPQRST
    VWXYZABCDEFGHIJKLMNOPQRSTU
    WXYZABCDEFGHIJKLMNOPQRSTUV
    XYZABCDEFGHIJKLMNOPQRSTUVW
    YZABCDEFGHIJKLMNOPQRSTUVWX
    ZABCDEFGHIJKLMNOPQRSTUVWXY
    

    and

    'R'
    

    There was another solution that looked interesting here, but I didn't trust it because I didn't understand it, so I'll unittest my code and the other code to see if it's reliable.

    def vig_2(row, col):
        return string.ascii_uppercase[(ord(row) + ord(col)) % 26]
    

    And unittested comparing both approaches. The second one (borrowed from NPE, to whom I now owe an upvote) is likely to be more performant if it is correct.:

    import unittest
    class VigTestCase(unittest.TestCase):
        def test_vigenere(self):
            self.assertEqual(vigenere('L', 'G'), 'R')
        def test_vigsquare(self):
            self.assertEqual(vigsquare(printable=False), 'ABCDEFGHIJKLMNOPQRSTUVWXYZBCDEFGHIJKLMNOPQRSTUVWXYZACDEFGHIJKLMNOPQRSTUVWXYZABDEFGHIJKLMNOPQRSTUVWXYZABCEFGHIJKLMNOPQRSTUVWXYZABCDFGHIJKLMNOPQRSTUVWXYZABCDEGHIJKLMNOPQRSTUVWXYZABCDEFHIJKLMNOPQRSTUVWXYZABCDEFGIJKLMNOPQRSTUVWXYZABCDEFGHJKLMNOPQRSTUVWXYZABCDEFGHIKLMNOPQRSTUVWXYZABCDEFGHIJLMNOPQRSTUVWXYZABCDEFGHIJKMNOPQRSTUVWXYZABCDEFGHIJKLNOPQRSTUVWXYZABCDEFGHIJKLMOPQRSTUVWXYZABCDEFGHIJKLMNPQRSTUVWXYZABCDEFGHIJKLMNOQRSTUVWXYZABCDEFGHIJKLMNOPRSTUVWXYZABCDEFGHIJKLMNOPQSTUVWXYZABCDEFGHIJKLMNOPQRTUVWXYZABCDEFGHIJKLMNOPQRSUVWXYZABCDEFGHIJKLMNOPQRSTVWXYZABCDEFGHIJKLMNOPQRSTUWXYZABCDEFGHIJKLMNOPQRSTUVXYZABCDEFGHIJKLMNOPQRSTUVWYZABCDEFGHIJKLMNOPQRSTUVWXZABCDEFGHIJKLMNOPQRSTUVWXY')
        def test_vig2(self):
            for i in string.ascii_uppercase:
                for j in string.ascii_uppercase:
                    self.assertEqual(vig_2(i, j), vigenere(i, j))
    
    unittest.main()
    ...
    ----------------------------------------------------------------------
    Ran 3 tests in 0.038s
    
    OK
    

    So it looks like NPE had a very good solution!