Practice Problem - Cryptography - Sample Solution

In [1]:
def caesar(string, shift):

    # We initialize an empty string to which we are going to add the new letters
    new_string = ""
    
    # Loop over all the letters in the string
    for letter in string:
        
        # We need to make sure that spaces stay intact
        if letter == ' ':
            new_letter = ' '
        else:
            
            # We convert the letter to its ASCII code and add the shift
            i = ord(letter) + shift
            
            # We need to make sure that we wrap around the alphabet
            if i > ord('z'):
                i -= 26
            elif i < ord('a'):
                i += 26
            
            # We convert the ASCII code back to a letter
            new_letter = chr(i)
            
        new_string += new_letter

    return new_string
     
print(caesar("pbatenghyngvbaf lbh unir fhpprrqrq va qrpelcgvat gur fgevat", -13))
congratulations you have succeeded in decrypting the string

Now for the string for which we don't know the shift:

In [2]:
for shift in range(26):
    print(shift, caesar("gwc uivioml bw nqvl bpm zqopb apqnb", -shift))
0 gwc uivioml bw nqvl bpm zqopb apqnb
1 fvb thuhnlk av mpuk aol ypnoa zopma
2 eua sgtgmkj zu lotj znk xomnz ynolz
3 dtz rfsflji yt knsi ymj wnlmy xmnky
4 csy qerekih xs jmrh xli vmklx wlmjx
5 brx pdqdjhg wr ilqg wkh uljkw vkliw
6 aqw ocpcigf vq hkpf vjg tkijv ujkhv
7 zpv nbobhfe up gjoe uif sjhiu tijgu
8 you managed to find the right shift
9 xnt lzmzfdc sn ehmc sgd qhfgs rghes
10 wms kylyecb rm dglb rfc pgefr qfgdr
11 vlr jxkxdba ql cfka qeb ofdeq pefcq
12 ukq iwjwcaz pk bejz pda necdp odebp
13 tjp hvivbzy oj adiy ocz mdbco ncdao
14 sio guhuayx ni zchx nby lcabn mbczn
15 rhn ftgtzxw mh ybgw max kbzam labym
16 qgm esfsywv lg xafv lzw jayzl kzaxl
17 pfl drerxvu kf wzeu kyv izxyk jyzwk
18 oek cqdqwut je vydt jxu hywxj ixyvj
19 ndj bpcpvts id uxcs iwt gxvwi hwxui
20 mci aobousr hc twbr hvs fwuvh gvwth
21 lbh znantrq gb svaq gur evtug fuvsg
22 kag ymzmsqp fa ruzp ftq dustf eturf
23 jzf xlylrpo ez qtyo esp ctrse dstqe
24 iye wkxkqon dy psxn dro bsqrd crspd
25 hxd vjwjpnm cx orwm cqn arpqc bqroc

It looks like the right shift was 8! Finally, here's how you could implement your own functions for ord and chr. It seems that a starts at an ASCII code of 97, so let's try and reproduce the results for the letters a to z:

In [3]:
def my_ord(s):
    letters = 'abcdefghijklmnopqrstuvwxyz'
    return letters.index(s) + 97

print(ord('f'), my_ord('f'))
102 102
In [4]:
def my_chr(i):
    letters = 'abcdefghijklmnopqrstuvwxyz'
    return letters[i-97]

print(chr(100), my_chr(100))
d d

Of course, these custom functions will only work for a to z and not for any other character or punctuation, but this is just practice for writing functions.