#Sage is a computer algebra system that is available free online via an interface called CoCalc. It uses a programming language and we can use Sage to run big computations that we could not finish by hand. It also has built-in functionality for a lot of the cipher systems that we will study, which will allow us to play with much larger examples!

#To use Sage for these cipher systems, we start with some setup commands. The first one tells Sage we are using letters for our messages, and names the alphabet so we can use it later. Start by "evaluating" this cell, which you do by pressing Shift + Return. alphabet = AlphabeticStrings()

#Sage has the Vigenere cipher built in. To use Sage to encrypt or decrypt you have to know the key length though. In this example, the key is "watson" which has length 6, so we will tell Sage we're using Vigenere on the alphabet with a key of length 6. (If our key was a different length, we would replace the 6 with the right length.) V = VigenereCryptosystem(alphabet,6)

#To encrypt a message, we need a key and message, so we first define the key and plaintext. These two commands tell Sage to interpret the key and message as part of our alphabet, and give them shortcut names k (for key) and P (for plaintext). [[We could give them different names (like key = or plaintext = or Bob = or X = or whatever).]] k = alphabet.encoding("watson") P = alphabet.encoding("the game is on")

#Now encipher the plaintext using the key. V.enciphering(k,P)

#If we want to have easy access to the ciphertext later, we can tell Sage to save it by naming the output. Below, I name the output of the enciphering command as C (for ciphertext). C = V.enciphering(k,P)

#We can also decipher a ciphertext message using the same key k. For example, to decipher the message we just encrypted, we could use this command. V.deciphering(k,C)

#If we had a different ciphertext, we would have to start by encoding it in our alphabet like we did with the key and plain text 4 cells ago. C2 = alphabet.encoding("ALXESAPAKQ")

#Then we could decipher it. V.deciphering(k,C2)

#The previous code is great if you know the key length and the key itself. What if you don't? #We need to count coincidences to find the key length. #Here are two new functions: coinc(text,s) counts the coincidences in "text" for a given shift "s". def coinc(text,s): z=0 for i in range(1,len(text)-s): if text[i]==text[i+s]: z=z+1 return z #The function allcoinc(text,max) outputs a list of the number of coincidences in "text" for every shift from 1 to "max". def allcoinc(text,max): colist=[] for s in range(1,max+1): colist.append(coinc(text,s)) return colist

#Here's a silly example of how the two functions work. TEXT = alphabet.encoding("aabbbcccc") #Some random sample text coinc(TEXT,2) #Find the number of coincidences in TEXT for a shift of 2 list = allcoinc(TEXT,10);list #Make a list of the number of coincidences for all shifts up to size 10. (That means we're assuming the maximum key length is 10.)

#We can look at individual elements of a list. #The number in the brackets is the location of the item in the list. We call it the index. What do you notice about the index versus the position in the list? list list[1]

#We can find the maximum number of coincidences by finding the maximum of the list. max(list)

#We need to know what shift gave the maximum number of coincidences. The command below finds the index of the maximum of the list. list.index(max(list))

#In this case, the maximum was the first element, in the index 0 spot. The index 0 corresponds with what shift? In general, how do we find the shift with the most coincidences from this command in Sage?

#Let's look at a less silly example. ciphertext=alphabet.encoding("ocwyikoooniwugpmxwktzdwgtssayjzwyemdlbnqaaavsuwdvbrflauplooubfgqhgcscmgzlatoedcsdeidpbhtmuovpiekifpimfnoamvlpqfxejsmxmpgkccaykwfzpyuavtelwhrhmwkbbvgtguvtefjlodfefkvpxsgrsorvgtajbsauhzrzalkwuowhgedefnswmrciwcpaaavogpdnfpktdbalsisurlnpsjyeatcuceesohhdarkhwotikbroqrdfmzghgucebvgwcdqxgpbgqwlpbdaylooqdmuhbdqgmyweuik")

#For that ciphertext, use allcoinc with max=20 to find the likely key length. allcoinc(ciphertext,20)

#So the most likely key length is 6. Now we do frequency analysis on groups of letters that are 6 apart. We can do this in Sage, but here's another more visual tool: #http://crypto.interactive-maths.com/kasiski-analysis-breaking-the-code.html (Runs on Flash, don't use Chrome.)

#Now try this one: The ciphertext is PLRUYIJENFSDTIRFUMVYRHERGESORVVVHPKVVRTULTKRTVRSUCKKBYXKGLZVJEJVGMCOASKNASNQNGVQGYIBNJKHELZVQIRWUFREOEXHUEUVBPMHQETLCLVUGLRWUEUERIESBWVGNWRFUECORRXHOCYLFRVSUINKRRIBUSCOVIIDAHZQGLVSESTHFWYHZEUHNHZVPSMHECREBYKFVTYHEWKKNXNHEISDFIURAZZJRRVURXREYIJVCITLSMTDYPPKRVVDYMQHQXYDGIEFVTYHEMEJCPRLAXVAGAZWUEBHLAFUQVVQQIIHQXYHPMGKRVKHKXJXONVFGXFPBHLONVRUVXYPRXZFQYILAKKKRGILZIRQJEIENFSDTISUBOVYVKVQRVVVNYKRXIPFVTYHEEJZRPCDFXYHZYTKJIRNRVTLCLVUGLRWVWTDYPVGIMXHAIIHPMGKRVKRQEPKVWULFGFYRVPZNWBHCXRPVPZWNVPVRGIHGEEGJEJQBXGXOPZVUIUFEIULGJFUGLVURWLOGARVVRJWREUJVZVQGSWUVIUUVGYNNWZVXMRSEYJVVEELAJRQGVPRSJZFRVNKBQRGRXYHFEDHQMJFBZVULWFPRCVDEWCDGII ︠f31ebb81-f6d1-42d3-bdbf-540ce85a4f29︠