diff --git a/.DS_Store b/.DS_Store index e6779ff..504a702 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/Python Modules/*Python Module Rubrics/.AffineEncrypt-rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.AffineEncrypt-rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 419579d..0000000 --- a/Python Modules/*Python Module Rubrics/.AffineEncrypt-rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,20 +0,0 @@ -{"backend_state":"init","connection_file":"/tmp/xdg-runtime-user/jupyter/kernel-47376500-153e-4f29-a243-dc7d5bc74fc6.json","kernel":"sage-9.1","kernel_error":"","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"6d7cbd","input":"Mod(m*P + k, 26)","pos":5,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"184ba3","input":"Mod(3*13 + 7, 26)","output":{"0":{"data":{"text/plain":"20"},"exec_count":1,"output_type":"execute_result"}},"pos":3,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"437d2a","input":"# Copy-paste your ShiftEncrypt function below and then make the designated changes.\ndef AffineEncrypt(plaintext, m, k):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n ciphertext = ''\n for letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(m*plaintext_number + k, 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\n print(ciphertext)","pos":7,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"c96dfc","input":"def AffineEncryptX(plaintext, m, k):\n ### Write your code here ###\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'\n ciphertext = ''\n for letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(m*plaintext_number + k, 28)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\n print(ciphertext)\nAffineEncryptX('YAYEUCLID!',15,2)","output":{"0":{"name":"stdout","output_type":"stream","text":"!C!GWE?KTA\n"}},"pos":16,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"ae4859","input":"### Write your code for (1)-(4) here ###\nAffineEncrypt('GOGRIFFINS',5,7)\nAffineEncrypt('CRYPTOGRAPHYISAWESOME',17,4)\nAffineEncrypt('STOPHAMMERTIME', 45, 32)\nAffineEncrypt('NANANANANANANANANABATMAN', 13, 0)","output":{"0":{"name":"stdout","output_type":"stream","text":"LZLOVGGVUT\nMHWZPICHEZTWKYEOUYIAU\nKDMFJGAAERDCAE\nNANANANANANANANANANANAAN\n"}},"pos":10,"type":"cell"} -{"cell_type":"markdown","id":"10cd6f","input":"Below, under the line `def AffineEncrypt(plaintext, m, k)`, copy-paste the code under the line `def ShiftEncrypt(plaintext, key)` from the `ShiftEncrypt` module (toward the very end, where you're defining the `ShiftEncrypt` function for the first time). Finally, change your code so instead of just adding $k$, we're multiplying by $m$ first and then adding $k$. Then run the chunk below (nothing should happen yet).","pos":6,"type":"cell"} -{"cell_type":"markdown","id":"18f9d8","input":"# Python Module: Affine Cipher Encryption","pos":1,"type":"cell"} -{"cell_type":"markdown","id":"2e0b9c","input":"Look at the way Sage enciphered \"STOPHAMMERTIME\" with multiplicative key 45 and additive key 32. Using modular arithmetic, rewrite the equation $C\\equiv 45P+32\\mod{26}$ to an equivalent equation in which each number is reduced mod 26. Write that equation below; you may use = instead of $\\equiv$ for congruence. Test your equation by encrypting the letter \"S\" with it on a separate sheet of paper. Does the resulting ciphertext match that of the function?","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"57d0a0","input":"## Now it's your turn!","pos":8,"type":"cell"} -{"cell_type":"markdown","id":"6d6c8d","input":"What happens to the word \"Batman\" in (4)? Why?","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"6f094c","input":"Every letter is converted to either N or A, where even letters are sent to 26 = A and odd letters are sent to 13 = N.","pos":14,"type":"cell"} -{"cell_type":"markdown","id":"8b9997","input":"Since 45 = 19 mod 26 and 32 = 6 mod 26, this cipher is equivalent to\n\nC = 19P + 6 mod 26","pos":12,"type":"cell"} -{"cell_type":"markdown","id":"9ded4e","input":"Now, the plaintext letter that we're encrypting is not always going to be M, and our keys are not always going to be $m=3$ and $k=7$. Below, write the code to multiply the variable $m$ times the variable $P$, then add $k$. Finally, wrap this code in the parentheses after the word Mod(). **Don't run the code chunk below.**","pos":4,"type":"cell"} -{"cell_type":"markdown","id":"a3e2fe","input":"# Rubric\n\n- **50 Points**: student has a working `AffineEncrypt` function\n- **10 Points**: student successfully reduces $45$ and $32\\mod{26}$\n- **10 Points**: student explains that the cipher $C\\equiv 13P\\mod{26}$ sends every number to either $26 = A$ or $13 = N$.\n- **30 Points**: student has a working `AffineEncryptX` function","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"cb9dd6","input":"Use your affine encryption function to encrypt the following messages with their corresponding keys:\n\n1. \"GOGRIFFINS\", $m = 5$, $k = 7$\n2. \"CRYPTOGRAPHYISAWESOME\", $m = 17$, $k = 4$\n3. \"STOPHAMMERTIME\", $m = 45$, $k = 32$.\n4. \"NANANANANANANANANABATMAN\", $m = 13$, $k = 0$. ","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"dbbd52","input":"The affine cipher is more complicated than the shift cipher. This is good for encryption security, but makes the cipher even more cumbersome to implement by hand. In this Python module, you'll write a function that takes as inputs a plaintext message $P$, multiplicative key $m$, and additive key $k$, and outputs the ciphertext $C$ via the equation $C\\equiv mP+k\\mod{26}$. Then, you'll encrypt several messages with this function. Finally, you'll develop a new function that allows you to use a larger alphabet to affine-encipher messages, for example by adding characters such as !, ?, and *.\n\nLet's begin by outlining the code necessary to encrypt a message using the affine cipher. Luckily, it only takes a small modification of your `ShiftEncrypt` code to encrypt using an affine cipher. Instead of adding $k$, our shift, and then reducing $\\mod 26$, we're first multiplying by $m$, adding $k$, and reducing the result $\\mod 26$.\n\nThe code to multiply 3 by 7 in Python is `3*7`. The code for the linear function $y=3x+7$ in Python is `y=3*x+7`.\n\nIf the plaintext letter in our code was 'n', which is 13 on our letter-to-number chart, write the code to encrypt 'n' using the affine cipher $C\\equiv 3P+7\\mod{26}$ in the chunk below. Test that, when you run the code, you get the number $20$, corresponding to the ciphertext letter U.","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"f9a76f","input":"Finally, define a function that uses a larger alphabet of your choice. For example, you could add the special characters ~!? to your alphabet. Be sure to adjust the modulus accordingly! Then, use this function to encrypt a message of your choice.","pos":15,"type":"cell"} -{"id":0,"time":1633492908614,"type":"user"} -{"last_load":1633492908586,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.BruteShift_rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.BruteShift_rubric.ipynb.sage-jupyter2 deleted file mode 100755 index d5c3a62..0000000 --- a/Python Modules/*Python Module Rubrics/.BruteShift_rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,35 +0,0 @@ -{"backend_state":"init","connection_file":"/tmp/xdg-runtime-user/jupyter/kernel-067d8615-1cb8-45d3-8aae-3d052cefbf3e.json","kernel":"sage-9.1","kernel_error":"","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"e9caaf","input":"","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"02052d","input":"# Input the ciphertext we want to decrypt\n\nciphertext = 'PBVHFUHW'","pos":8,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"7e0e14","input":"# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'","pos":6,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"c36ca6","input":"def ShiftDecrypt(ciphertext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n plaintext = ''\n for letter in ciphertext:\n ciphertext_number = alph.find(letter)\n plaintext_number = Mod(ciphertext_number - key, 26)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n print(plaintext)","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":11,"id":"9f9c32","input":"# this is just one possible example\n\n# first redefine the `ShiftDecryptX` function from Exercise 2 of the ShiftDecrypt module\n\ndef ShiftDecryptX(ciphertext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n plaintext = ''\n for letter in ciphertext:\n ciphertext_number = alph.find(letter)\n plaintext_number = Mod(ciphertext_number - key, 29)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n print(plaintext)\n \n# then define the BruteShiftX function to try every possible shift modulo the alphabet size from their ShiftDecryptX function (or whatever they've named it):\n\ndef BruteShiftX(ciphertext):\n for key in range(0,29):\n ShiftDecryptX(ciphertext, key)","pos":28,"type":"cell"} -{"cell_type":"code","exec_count":12,"id":"b8cc8c","input":"# Write the code to decrypt your encrypted message here.\nBruteShiftX('KMLICW')","output":{"0":{"name":"stdout","output_type":"stream","text":"KMLICW\nJLKHBV\nIKJGAU\nHJIF!T\nGIHE?S\nFHGD~R\nEGFCZQ\nDFEBYP\nCEDAXO\nBDC!WN\nACB?VM\n!BA~UL\n?A!ZTK\n~!?YSJ\nZ?~XRI\nY~ZWQH\nXZYVPG\nWYXUOF\nVXWTNE\nUWVSMD\nTVURLC\nSUTQKB\nRTSPJA\nQSROI!\nPRQNH?\nOQPMG~\nNPOLFZ\nMONKEY\nLNMJDX\n"}},"pos":30,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"53ddf3","input":"# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\n# Input the ciphertext we want to decrypt\n\nciphertext = 'PBVHFUHW'\n\nfor shift in range(0,26):\n ShiftDecrypt(ciphertext, shift)","output":{"0":{"name":"stdout","output_type":"stream","text":"PBVHFUHW\nOAUGETGV\nNZTFDSFU\nMYSECRET\nLXRDBQDS\nKWQCAPCR\nJVPBZOBQ\nIUOAYNAP\nHTNZXMZO\nGSMYWLYN\nFRLXVKXM\nEQKWUJWL\nDPJVTIVK\nCOIUSHUJ\nBNHTRGTI\nAMGSQFSH\nZLFRPERG\nYKEQODQF\nXJDPNCPE\nWICOMBOD\nVHBNLANC\nUGAMKZMB\nTFZLJYLA\nSEYKIXKZ\nRDXJHWJY\nQCWIGVIX\n"}},"pos":16,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"d09feb","input":"range(0,26)","output":{"0":{"data":{"text/plain":"[0,\n 1,\n 2,\n 3,\n 4,\n 5,\n 6,\n 7,\n 8,\n 9,\n 10,\n 11,\n 12,\n 13,\n 14,\n 15,\n 16,\n 17,\n 18,\n 19,\n 20,\n 21,\n 22,\n 23,\n 24,\n 25]"},"exec_count":2,"output_type":"execute_result"}},"pos":12,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"acb1a0","input":"for number in range(1,24):\n print(number)","output":{"0":{"name":"stdout","output_type":"stream","text":"1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20\n21\n22\n23\n"}},"pos":4,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"da124b","input":"def BruteShift(ciphertext):\n for shift in range(0,26):\n ShiftDecrypt(ciphertext, shift)","pos":24,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"d486e7","input":"BruteShift('DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB')","output":{"0":{"name":"stdout","output_type":"stream","text":"DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB\nCKKZYKZAOIQOPJKPUEAHZPKXNQPABKNYA\nBJJYXJYZNHPNOIJOTDZGYOJWMPOZAJMXZ\nAIIXWIXYMGOMNHINSCYFXNIVLONYZILWY\nZHHWVHWXLFNLMGHMRBXEWMHUKNMXYHKVX\nYGGVUGVWKEMKLFGLQAWDVLGTJMLWXGJUW\nXFFUTFUVJDLJKEFKPZVCUKFSILKVWFITV\nWEETSETUICKIJDEJOYUBTJERHKJUVEHSU\nVDDSRDSTHBJHICDINXTASIDQGJITUDGRT\nUCCRQCRSGAIGHBCHMWSZRHCPFIHSTCFQS\nTBBQPBQRFZHFGABGLVRYQGBOEHGRSBEPR\nSAAPOAPQEYGEFZAFKUQXPFANDGFQRADOQ\nRZZONZOPDXFDEYZEJTPWOEZMCFEPQZCNP\nQYYNMYNOCWECDXYDISOVNDYLBEDOPYBMO\nPXXMLXMNBVDBCWXCHRNUMCXKADCNOXALN\nOWWLKWLMAUCABVWBGQMTLBWJZCBMNWZKM\nNVVKJVKLZTBZAUVAFPLSKAVIYBALMVYJL\nMUUJIUJKYSAYZTUZEOKRJZUHXAZKLUXIK\nLTTIHTIJXRZXYSTYDNJQIYTGWZYJKTWHJ\nKSSHGSHIWQYWXRSXCMIPHXSFVYXIJSVGI\nJRRGFRGHVPXVWQRWBLHOGWREUXWHIRUFH\nIQQFEQFGUOWUVPQVAKGNFVQDTWVGHQTEG\nHPPEDPEFTNVTUOPUZJFMEUPCSVUFGPSDF\nGOODCODESMUSTNOTYIELDTOBRUTEFORCE\nFNNCBNCDRLTRSMNSXHDKCSNAQTSDENQBD\nEMMBAMBCQKSQRLMRWGCJBRMZPSRCDMPAC\n"}},"pos":26,"type":"cell"} -{"cell_type":"markdown","id":"0fffc9","input":"Now, go back to the `ShiftEncrypt` Sage module. What was our next step in that case? Would we be able to use the same next step here? Why or why not? Write your answer below.","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"160487","input":"3. Finally, test your new function by first using your beefed-up `ShiftEncrypt` function from Exercise 2 of that assignment to encrypt a message. Then, in the box below, input the encrypted message and run your beefed-up `BruteDecrypt` function from Exercise $2$ above to decrypt it. Did you get the plaintext you started with? Why or why not?","pos":29,"type":"cell"} -{"cell_type":"markdown","id":"200a1e","input":"## Exercises\n\n1. Use your shiny new function to decrypt the phrase \"DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB\" (spaces removed) given that it was encrypted with a shift cipher. Write the code you use to do this and run that code below.","pos":25,"type":"cell"} -{"cell_type":"markdown","id":"21868e","input":"","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"2255b4","input":"# Rubric\n\n- (50 points) Student writes a working `BruteShift` function\n- (50 points) Student writes an extended-alphabet `BruteShift` function and verifies it successfully brute-forces the ciphertext generated by their extended-alphabet `ShiftEncrypt` function","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"243421","input":"Here, describe whether you got the plaintext you started with and why or why not.","pos":31,"type":"cell"} -{"cell_type":"markdown","id":"2ad841","input":"2. Below, define a function that uses brute force to decrypt a message that was encrypted using the larger alphabet from Exercise $2$ from the `ShiftDecrypt` module. Be sure to adjust the modulus accordingly!","pos":27,"type":"cell"} -{"cell_type":"markdown","id":"2c4f07","input":"## The `range` command\n\nIt would be quite a pain to write out all those numbers each time we wanted to tell Python to try all shifts. Thankfully, Python has a built-in command that denotes all numbers in a given range.\n\nSay you want the numbers 0, 1, 2, 3, 4, 5, and 6. The \"Pythonic\" way of doing this is `range(0,7)`. Notice that the second number in the parentheses is never reached. So Python's \"syntax\" (the language it uses) for number ranges is ``range(first number, last number + 1)``. \n\nBelow, write the Python command to print the numbers 1 through 23. Then run your command and see if it works. Remember that ``print(7)`` is the command to print the number 7. If your code doesn't work, talk to a group member or to your instructor.","pos":3,"type":"cell"} -{"cell_type":"markdown","id":"34754d","input":"## The `BruteShift` function\n\nNow, we'll write a function that allows us to brute force any intercepted shift-enciphered message. As before, when shift ciphers are used in the real world, the ciphertext is almost certain not to be 'PBVHFUHW'. Instead of this specific ciphertext, we want to allow ourselves the freedom to *define* whatever ciphertext we want. In other words, we want ``ciphertext`` to be the *input* to a function.\n\nWe can almost exactly recycle our code from above, where we brute-force decrypted 'PBVHFUHW'. However, we'll need to replace any references to specific ciphertext with the variable `ciphertext`.\n\nIn the code box below, remove all references to the ciphertext 'PBVHFUHW', leaving only references to the variable `ciphertext`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below.","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"58fc2e","input":"It looks like we're going to have to try every possible shift between $0$ and $25$, including $0$ and $25$. Below, write the `range` command that describes the range of numbers $0,1,2,\\dots,25$. Then test your command by running it and verifying that it prints the correct set of numbers. If it doesn't work, talk to someone.","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"5b9488","input":"Below, based on your investigations so far, discuss how secure you think the shift cipher is. Would you use the shift cipher to send a message to a friend? To store the password to your Facebook/Instagram/Snapchat account? What about to send military messages? Explain your answers.","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"77cd88","input":"Test your code by running it. Can you figure out what the plaintext corresponding to the ciphertext 'PBVHFUHW'? If so, write that plaintext below and discuss how you found it. If not, explain why not.","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"77e570","input":"What else do we need? Well, we have to tell the computer what plaintext we want to decrypt. Just like we did in the previous Sage module, we label our plaintext with the variable ``plaintext``. After we type the line below, every time we write ``plaintext``, Sage will replace it with ``'PBVHFUHW'``. That way, we don't have to remember and re-type the ciphertext every time we want to refer to it.","pos":7,"type":"cell"} -{"cell_type":"markdown","id":"86ad00","input":"## Testing all shifts using a `for` loop\n\nGreat! You've found the code that describes the range of numbers $0,1,2,3,\\dots,25$. Now we want the computer to try every possible one of these numbers as a shift. In other words, `for` every one of these numbers, we want to try the ShiftDecrypt process we encoded in the last module.\n\nHere's a great thing about Python: it's \"stackable\". In other words, now that we've written the code to decrypt a message with known key, we don't need to rewrite it again. We can simply copy/paste that code into this module. Then, whenever we want to try a specific key, say $7$, on a specific message, say \"GJKRGE\", we can just write\n\n``ShiftDecrypt('GJKRGE',7)``.\n\nBelow, copy/paste your function from code chunk (1.7) of the ShiftDecrypt module and run it. (It shouldn't do anything, but running it in this worksheet means the `ShiftDecrypt` command is now accessible to us for the rest of the module.)","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"932324","input":"Time for our `for` loop! For every possible shift between $0$ and $25$, we want to try `ShiftDecrypt`ing the ciphertext using that shift. \n\nUnderneath the `for` loop below, tabbed over, write the code that would allow you to run the function `ShiftDecrypt` on the variable `ciphertext` with the key being the variable `shift`. (Basically, you can ignore all this stuff about \"variables\" when writing the code and just put the names of the variables in the function.)","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"9ffc24","input":"The chunk above should have again spit out the $26$ possible plaintexts corresponding to the plaintext 'PBVHFUHW'. This is because we've already told Python in the previous section that `ciphertext` is a placeholder for the text 'DOFCOMWUYMUL'. \n\nAs before, to save us from having to write out all this code anytime we want to decrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to brute-force decrypt the message 'AJTQETA',\n\n``BruteShift('AJTQETA')``\n\nJust like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the y-value $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n\nRemember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once.","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"a72fb2","input":"","pos":20,"type":"cell"} -{"cell_type":"markdown","id":"b40dfd","input":"Let's see how to decrypt the message 'PBVHFUHW' if all we know is that it was encrypted with a shift cipher (unknown shift). First, just like with encryption, we want to define a cipher alphabet: in this case, all capital English letters.","pos":5,"type":"cell"} -{"cell_type":"markdown","id":"b99ec8","input":"*Our next step in the `ShiftEncrypt` module was to tell the program our key. We can't do that here because we don't know the key.*","pos":10,"type":"cell"} -{"cell_type":"markdown","id":"ba98a6","input":"- The plaintext must be the only readable English text output by the `for` loop: \"MYSECRET\".","pos":18,"type":"cell"} -{"cell_type":"markdown","id":"bb992d","input":"# Decrypting Shift Ciphers Using Brute Force\n\n## What is brute force?\n\nLet's say you intercept a message that you know was encrypted with a shift cipher, but you don't know the key. Is it possible to just try every possible key until you figure out what the message says?\n\nWith shift ciphers and some other simple types of ciphers, the answer is yes! This is a good reason that the shift cipher is not currently used for military purposes. It was all well and good for Julius Caesar when no one was aware that shift ciphers existed, but now that they're commonly known, any shift-ciphered message could be broken by a (not particularly bright) computer in a few seconds.\n\nBreaking a cipher by **brute force** (or a **brute-force attack**) means trying to decrypt a message using all possible keys until you find a key that generates reasonable English plaintext. \n\nLet's start with a specific example. Say you encounter the ciphertext \"PBVHFUHW\", and you know it's been encrypted using a shift cipher (with unknown key). How would you execute a brute-force attack on this message with pen and paper? In the text box below, write out the steps you would take. How many possible keys would we have to try to decrypt a message that has been enciphered using an unknown shift cipher? Why?","pos":1,"type":"cell"} -{"id":0,"time":1633493582979,"type":"user"} -{"last_load":1632887917039,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm-Rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm-Rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 1aa4873..0000000 --- a/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm-Rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,30 +0,0 @@ -{"backend_state":"init","kernel":"sage-9.4","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":2},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython2","version":"2.7.15"}},"trust":false,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"24b9b9","input":"# 1.3\nwhile a != 0:\n b = b % a\n a,b = b,a\nprint b","pos":20,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"4ca71d","input":"# 1.2\nwhile a != 0:\n b = b % a\n a,b = b,a","pos":18,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"7a3019","input":"# 1.1\nwhile a != 0:\n b = b % a","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"7f4b66","input":"b = b % a","pos":9,"type":"cell"} -{"cell_type":"code","exec_count":10,"id":"ee18d2","input":"#3. \nEA(12341234, 543513543)","output":{"0":{"name":"stdout","output_type":"stream","text":"73\n"}},"pos":26,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"c2501c","input":"# 2.\n548%32","output":{"0":{"data":{"text/plain":"4"},"exec_count":3,"output_type":"execute_result"}},"pos":6,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"59a688","input":"# 3.\n91042%8321","output":{"0":{"data":{"text/plain":"7832"},"exec_count":4,"output_type":"execute_result"}},"pos":7,"type":"cell"} -{"cell_type":"code","exec_count":5,"id":"45faf8","input":"# 1.\n263%123","output":{"0":{"data":{"text/plain":"17"},"exec_count":5,"output_type":"execute_result"}},"pos":5,"type":"cell"} -{"cell_type":"code","exec_count":6,"id":"d17ff0","input":"x = 1\nwhile x < 4:\n print x\n x = x + 1","output":{"0":{"name":"stdout","output_type":"stream","text":"1\n2\n3\n"}},"pos":12,"type":"cell"} -{"cell_type":"code","exec_count":7,"id":"084a3a","input":"# 1.4 Defining a function\ndef EA(a,b):\n while a != 0:\n b = b % a\n a,b = b,a\n print b","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":8,"id":"f7b8dd","input":"#1.\nEA(213, 543)","output":{"0":{"name":"stdout","output_type":"stream","text":"3\n"}},"pos":24,"type":"cell"} -{"cell_type":"code","exec_count":9,"id":"e3c102","input":"#2.\nEA(32132, 54254)","output":{"0":{"name":"stdout","output_type":"stream","text":"2\n"}},"pos":25,"type":"cell"} -{"cell_type":"markdown","id":"02ed3c","input":"**The `Mod` or % functions reduce $b\\mod{a}$, which is the same thing as taking the remainder of $b/a$.**","pos":3,"type":"cell"} -{"cell_type":"markdown","id":"105458","input":"In Python, the code for \"reduce a modulo b\" is `Mod(a,b)` or, equivalently, `a % b`. For example, to reduce $43 \\mod 26$, you'd write `Mod(43,26)` or `43 % 26`. (Here, when you see the \"percent\" symbol, think of division and finding a remainder.)\n\nBelow, write and run the code to reduce each of the following:\n1. $263 \\mod 123$\n2. $548 \\mod 32$\n3. $91042 \\mod 8321$","pos":4,"type":"cell"} -{"cell_type":"markdown","id":"17e3fe","input":"The goal of this Python module is to give you a greater understanding of the Euclidean Algorithm by designing a function to compute the greatest common divisor $\\gcd(a,b)$ of two whole numbers $a$ and $b$.\n\nRecall the steps in the Euclidean Algorithm when computing $\\gcd(a,b)$, assuming $a < b$:\n\n1. Divide the larger of $a$ and $b$ by the smaller. Since we're assuming $a < b$, we'd divide $b$ by $a$.\n2. Keep the remainder and $a$. Since the remainder of $b/a$ is smaller than $a$, let's rename $a$ to $b$, and call the remainder our new $a$.\nFor example, after dividing $b=13$ by $a=5$, we get a remainder of $3$. We'd then rename $a=3$, $b=5$.\n3. Repeat this process until one of your numbers becomes $0$. Since at each stage we rename $a$ to be the smaller of the two numbers, we'd repeat until $a=0$.\n4. At this point, the gcd is the other (nonzero) number, $b$.\n\nWe need to figure out how to ask Python to take the remainder of $b/a$. What mathematical process do we already know how to do in Python that would give us the remainder? Write your answer below.","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"2368bf","input":"Step 2 is to repeat Step 1 \"until one of our numbers is 0\". The way we do this in Python is with a *`while` loop*. A `while` loop says \"run the code below as long as some statement is true\". Contrast with a `for` loop, which runs e.g. for every number in a given range. In a `while` loop, the loop will stop once the specified condition is *no longer* met.\n\nJust like a `for` loop, when beginning a `while` loop, you enter a colon. Everything that should be repeated is tabbed over. Once the loop ends, anything you want Python to do afterwards is not tabbed over.\n\nHere's a simple example of a while loop:\n\n```\nx = 1\nwhile x < 4:\n print x\n x = x + 1\n```\n\nThis code says \"start with $x=1$. Then, as long as $x$ is less than $4$, print out $x$, then replace $x$ with $x+1$. Stop doing this as soon as $x\\geq 4$.\" What do you think this code will do? Write your guess below. Then run the code in the next box to see what it does. Did you guess right?","pos":10,"type":"cell"} -{"cell_type":"markdown","id":"4f2b9a","input":"Think through how the Euclidean Algorithm would work for $a=2,b=3$. First it would reduce $b\\mod{a}$, getting a new $b$-value of $1$. At this point, $a=2$ and $b=1$. What happens at this stage if we try to reduce $b\\mod{a}$? Explain your answer.","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"6124ee","input":"**The code should spit out [1, 2, 3] and then stop, since when $x=3$ the `while loop` would print $3$, replace $3$ with $4$, and at that point the condition $x<4$ would no longer be met.**","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"679c2e","input":"In our case, we want to run code as long as $a \\neq 0$, since this means the code will stop when $a=0$. In Python, \"not equal to\" is written `!=`. (The exclamation mark is \"crossing out\" the equals sign.) So, for example, to say \"$x$ is not equal to $5$\", you'd write `x != 5`.\n\nBelow, write the first line of a while loop that will run as long as $a \\neq 0$. Remember to put a colon after the first line, and don't run your code yet! Underneath your first line, tabbed over, write the code to replace $b$ with $b \\mod a$. This code corresponds to steps 1 and 2 of our algorithm.","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"91e3da","input":"# The Euclidean Algorithm with Python","pos":1,"type":"cell"} -{"cell_type":"markdown","id":"98a501","input":"We're almost done! After completing steps 1 and 2, the last step is to have the code spit out the nonzero number. Since our loop runs *until* $a = 0$, at the end of our loop, $a = 0$. So $b$ is the nonzero number we want.\n\nRemember that the Pythonic expression for \"spit `something` out\" is `print something` (here you'd replace the variable `something` with whatever variable you want to return). Below, copy-paste your code from (1.2), but this time, add code below your while loop to spit out the number $b$, which will be our gcd. **Don't run your code yet**; we'll do that once we define a function below.","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"a56c92","input":"# Rubric\n\n- **60 points**: student has a working Euclidean Algorithm function\n- **40 points**: student successfully runs the function to compute each of:\n - $\\gcd(213,543)$\n - $\\gcd(32132,54254)$\n - $\\gcd(12341324,543513543)$","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"bea613","input":"For the reason you mentioned above, if we continued replacing $b$ with $b\\mod{a}$ at each step, never changing the roles of $a$ or $b$, the code would never stop running. This is because reducing a smaller number modulo a bigger number *doesn't change the smaller number*. On a clock with $2$ hours, 1:00 is just 1:00!\n\nThe way we'll fix this is by telling Python to interchange the roles of $a$ and $b$ after each reduction step. The code to do this is `a,b=b,a`. This tells Python to take the value to the left of the first comma ($a$) and replace it with the value to the left of the second comma ($b$). Simultaneously, this code tells Python to replace the value to the *right* of the first comma ($b$) with the value to the *right* of the second comma ($a$). Overall, thus, the code interchanges the roles of $a$ and $b$.\n\nBelow, copy-paste your code from (1.1), but then add the code to interchange the values of $a$ and $b$ tabbed over **below the `while` loop**.","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"c65988","input":"And for your last question on this assignment, test your brand-new gcd function on a few pairs of numbers! In the code chunk below, tell your function to compute the following:\n1. $\\gcd(213,543)$\n2. $\\gcd(32132,54254)$\n3. $\\gcd(12341324,543513543)$\n\nRemember that, in order to use a function you've written, you have to write the name of the function, open parentheses, inputs to the function separated by commas, and close parentheses. For example, to run a function called `zookeeper` on the inputs `monkey, lion, tiger`, you'd write\n\n```\nzookeeper(monkey, lion, tiger)\n```","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"d71f89","input":"**We'd get $1\\mod{2}=1$. Nothing would change.**","pos":16,"type":"cell"} -{"cell_type":"markdown","id":"ee5b80","input":"OK, last step! Let's make a *function* out of your code so we don't need to write all of the code out every time we want to compute a gcd. Do you remember how functions work? The first line looks like `def name_of_function(input1, input2):`. Everything under the first line that's part of the function gets tabbed over.\n\nIn the code block below, define a function called `EA` which takes as inputs two whole numbers $a$ and $b$ where $a\\lt b$ and spits out $\\gcd(a,b)$. (Hint: after writing the line which `def`s your function, just copy/paste your code from earlier below that line. Make sure you tab everything under the `def` line over once, and you'll need another tab underneath the `while` line!)\n\nActually, Sage (the app we're using to code in Python) already has a built-in `gcd` function. **So it's important we don't call our function `gcd`.**","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"fdaba4","input":"Now, let's write code for each step in the Euclidean Algorithm. For now, let's assume that $a\\neq 0$ and that $a\\lt b$.\n\nIn the first step of the Euclidean Algorithm, we replace $b$ with $b\\mod a$. In Python, \"replace $x$ with $y$\" is written `x = y`.\n\nBelow, write the code to replace $b$ with $b \\mod a$.","pos":8,"type":"cell"} -{"id":0,"time":1633668002625,"type":"user"} -{"last_load":1633667173838,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm_Rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm_Rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 45ca046..0000000 --- a/Python Modules/*Python Module Rubrics/.Euclidean_Algorithm_Rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,24 +0,0 @@ -{"backend_state":"running","kernel":"sage-8.8","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":244744192},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":2},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython2","version":"2.7.13"}},"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"063e4d","input":"","pos":10,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"1b9dfb","input":"b = b % a","pos":3,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"723dd9","input":"","pos":16,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"c2cbf6","input":"","pos":12,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"e1feb1","input":"","pos":21,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"e7fd51","input":"263 % 123\n548 % 32\n91042 % 8321","pos":1,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"f782e4","input":"","pos":14,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":3,"id":"ab310e","input":"x = 0\nwhile x < 4:\n print x\n x = x + 1","output":{"0":{"name":"stdout","output_type":"stream","text":"0\n1\n2\n3\n"}},"pos":6,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":4,"id":"b5c726","input":"while b != 0:\n b = b % a","output":{"0":{"ename":"NameError","evalue":"name 'b' is not defined","output_type":"error","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32mwhile\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 2\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mb\u001b[0m \u001b[0;34m%\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0ma\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mb\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mb\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0ma\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mNameError\u001b[0m: name 'b' is not defined"]}},"pos":8,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":6,"id":"bbe6ad","input":"gcd(213, 543)","output":{"0":{"data":{"text/plain":"3"},"exec_count":6,"output_type":"execute_result"}},"pos":18,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":7,"id":"ed78f4","input":"gcd(32132, 54254)","output":{"0":{"data":{"text/plain":"2"},"exec_count":7,"output_type":"execute_result"}},"pos":19,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":8,"id":"86db79","input":"def gcd(a,b):\n while a != 0:\n b = b % a\n a,b = b,a\n return b","pos":15,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":9,"id":"d5af9a","input":"gcd(12341324, 543513543)","output":{"0":{"data":{"text/plain":"1"},"exec_count":9,"output_type":"execute_result"}},"pos":20,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"038eaa","input":"Step 2 is to repeat Step 1 \"until one of our numbers is 0\". The way we do this in Python is with a *while loop*. A while loop specifies a condition under which the code will stop. Until that condition is met, the code will repeat itself.\n\nJust like a for loop, when beginning a while loop, you enter a colon. Everything that should be repeated is tabbed over. Once the loop ends, anything you want Python to do afterwards is not tabbed over.\n\nHere's a simple example of a while loop:\n\n```\nx = 0\nwhile x < 4:\n x = x + 1\n```\n\nThis code says \"as long as $x$ is less than $4$, replace $x$ with $x+1$\". What do you think this code will do if you ask it to print out the number $x$ at each stage of the loop? Write your guess below. Then run the code in the next box to see what it does. Did you guess right?","pos":4,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"17b4c8","input":"OK, last step! If your code worked above, let's make a *function* out of it so we don't need to write all of the code out every time we want to compute a gcd. Do you remember how functions work? The first line looks like `def name_of_function(input1, input2):`. Everything under the first line that's part of the function gets tabbed over.\n\nIn the code block below, define a function called $\\gcd$ which takes as inputs two whole numbers $a$ and $b$ where $a\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# 1.2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# counts occurences of each letter\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mletter_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m26\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0malphabet\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mNameError\u001b[0m: name 'letter_list' is not defined"]}},"pos":7,"type":"cell"} -{"cell_type":"code","exec_count":13,"id":"05fa09","input":"# 1.3\n# pair each letter of the alphabet with its frequency in a new list\n\n## Write your code here ##","pos":9,"type":"cell"} -{"cell_type":"code","exec_count":17,"id":"bd02a2","input":"def freq_analysis(message):\n ## copy-paste and edit your code here to define the function ##","pos":15,"type":"cell"} -{"cell_type":"code","exec_count":19,"id":"581548","input":"# 1.4\n\n# sort by decreasing order of relative frequency and return the frequencies together with the corresponding ciphertext letters\n\n## write your code here ##","pos":11,"type":"cell"} -{"cell_type":"code","exec_count":21,"id":"f11a42","input":"# 1.5\n## Copy-paste your code here ##","pos":13,"type":"cell"} -{"cell_type":"code","exec_count":22,"id":"5719b4","input":"#Tests\n\n## write your code here ##","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"0496a6","input":"Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)","pos":4,"type":"cell"} -{"cell_type":"markdown","id":"354db7","input":"Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n\nThe code to add 1 to the 19th entry of `count_list` is:\n\n```\ncount_list[19] += 1\n```\n\nHere, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1.\n\n**In place of the line \"`## write your code here ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.**","pos":6,"type":"cell"} -{"cell_type":"markdown","id":"3582d0","input":"The code above spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n\n```\n[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n```\n\nwhere the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the 18th spot reflects the count of $T = 18$.\n\nDo you see any problems? \n\nIt's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n\nThe way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n\nSimilarly, we'll get the entries \n\n```\n['B',0], ['C',0], ['D',0], ['E',1],\n```\n\netc.\n\nThe Python command to merge two lists together is `zip(list1, list2)`. **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**.","pos":8,"type":"cell"} -{"cell_type":"markdown","id":"66bd91","input":"Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes.\n\nThe way Python sorts lists is with the command \n\n```\n{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by])\n```\n\nHere, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n\nIn this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is the first column in the list, since `alphabet` is considered the zeroth column).\n\nBelow, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`.","pos":10,"type":"cell"} -{"cell_type":"markdown","id":"76348c","input":"Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n\nAs usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n\n**Copy-paste your code from (1.5) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**","pos":14,"type":"cell"} -{"cell_type":"markdown","id":"82d1f9","input":"**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n\nFor example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`.","pos":16,"type":"cell"} -{"cell_type":"markdown","id":"bc13c8","input":"## Python Module: Frequency Analysis\n\nFrequency analysis is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n\nFor example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be an encrypted body of text that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n\nTo begin, let's look at the code for a frequency count of the text \"TEST\".\n\nWe'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n\nIt's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 to our `count_list` 26 times.\n\nDo you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses after `range` in the line `for i in range():`**","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"e69470","input":"For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about e.g. spaces).\nWe do this by going through our message letter by letter and adding each letter to our list.\nThis is done using the command `.append`. \n\nWhenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n\nIf our list were called `cool_list`, the code to do this would be as follows:","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"ea030b","input":"Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.4) above in order and run it in order to perform a frequency count on the message `'TEST'`.**","pos":12,"type":"cell"} -{"id":0,"time":1636497473357,"type":"user"} -{"last_load":1636497473589,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.Frequency_Analysis_Rubric2.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.Frequency_Analysis_Rubric2.ipynb.sage-jupyter2 deleted file mode 100755 index 03a05d4..0000000 --- a/Python Modules/*Python Module Rubrics/.Frequency_Analysis_Rubric2.ipynb.sage-jupyter2 +++ /dev/null @@ -1,23 +0,0 @@ -{"backend_state":"running","kernel":"sage-9.1","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":236634112},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":2},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython2","version":"2.7.15"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"1cb490","input":"#Tests\n\n#1.\n## write your code here ##","pos":17,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"1cfae8","input":"# 1.2\n## Write your code here ##\nletter_list = []\n# add every letter in the message to the list\nfor letter in message:\n letter_list.append(letter)","pos":5,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"2d5f75","input":"# 1.1\nalphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\nmessage = \"TEST\"\n\ncount_list = []\n\n## Edit the line of code below ##\nfor i in range(0,26):\n count_list.append(0)","pos":1,"scrolled":true,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"33fd81","input":"# 1.5\n\n# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n\nsorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\nprint sorted_letter_freq\n\n## write your code here ##","pos":11,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"4507cc","input":"#2.\n## write your code here ##","pos":18,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"4b24d5","input":"#3.\n## write your code here ##","pos":19,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"65a31a","input":"# 1.4\n# pair each letter of the alphabet with its frequency in a new list\nletter_freq = zip(alphabet, count_list)\n## Write your code here ##","pos":9,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"872aea","input":"# 1.3\n# counts occurences of each letter\nfor letter in letter_list:\n for i in range(0,26):\n if letter == alphabet[i]:\n count_list[i] += 1\n ","pos":7,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":0,"id":"ef0fb0","input":"def freq_analysis(message):\n # 1.1\n alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n count_list = []\n\n ## Edit the line of code below ##\n for i in range(0,26):\n count_list.append(0)\n\n # 1.2\n ## Write your code here ##\n letter_list = []\n # add every letter in the message to the list\n for letter in message:\n letter_list.append(letter)\n\n# 1.3\n# counts occurences of each letter\n for letter in letter_list:\n for i in range(0,26):\n if letter == alphabet[i]:\n count_list[i] += 1\n\n# 1.4\n# pair each letter of the alphabet with its frequency in a new list\n letter_freq = zip(alphabet, count_list)\n## Write your code here ##\n\n# 1.5\n\n# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n\nsorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\nprint sorted_letter_freq","pos":15,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":1,"id":"352c4e","input":"# 1.1\nalphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\nmessage = \"TEST\"\n\ncount_list = []\n\n## Edit the line of code below ##\nfor i in range(0,26):\n count_list.append(0)\n\n# 1.2\n## Write your code here ##\nletter_list = []\n# add every letter in the message to the list\nfor letter in message:\n letter_list.append(letter)\n\n# 1.3\n# counts occurences of each letter\nfor letter in letter_list:\n for i in range(0,26):\n if letter == alphabet[i]:\n count_list[i] += 1\n\n# 1.4\n# pair each letter of the alphabet with its frequency in a new list\nletter_freq = zip(alphabet, count_list)\n## Write your code here ##\n\n# 1.5\n\n# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n\nsorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\nprint sorted_letter_freq","output":{"0":{"name":"stdout","output_type":"stream","text":"[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n"}},"pos":13,"state":"done","type":"cell"} -{"cell_type":"code","exec_count":12,"id":"71af4a","input":"# start with a blank list\ncool_list = []\n\n# add every letter in the message to the list\nfor letter in message:\n cool_list.append(letter)","pos":3,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"18d721","input":"Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.5) above in order and run it in order to perform a frequency count on the message `'TEST'`.**","pos":12,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"5cffdf","input":"Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes. Then we could immediately tell what the most common ciphertext letter was and guess it came from plaintext e.\n\nThe way Python sorts lists is with the command \n\n```\n{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by], reverse = True)\n```\n\nHere, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n\nIn this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is numbered as the first column in the list, since `alphabet` is considered the zeroth column). \n\nThe `reverse = True` line means that letters with higher frequencies will come first in the list instead of last, which is the default option.\n\nBelow, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`.","pos":10,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"675c48","input":"Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)","pos":4,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"8486bc","input":"The code above spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n\n```\n[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n```\n\nwhere the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the $19$th spot reflects the count of $T = 19$.\n\nDo you see any problems? \n\nIt's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n\nThe way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n\nSimilarly, we'll get the entries \n\n```\n['B',0], ['C',0], ['D',0], ['E',1],\n```\n\netc.\n\nThe Python command to merge two lists together is `zip(list1, list2)` (think of literally taking the two lists with a zipper between them and zipping up the zipper to join them side by side). **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**.","pos":8,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"8fc49c","input":"**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n\nFor example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`.","pos":16,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"a2c3cf","input":"For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about spaces).\nWe do this by going through our message letter by letter and adding each letter to our list.\nThis can be done using the command `.append`, just as we used for numbers above.\n\nWhenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n\nIf our list were called `cool_list`, the code to do this would be as follows:","pos":2,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"b101ed","input":"## Python Module: Frequency Analysis\n\n**Frequency analysis** is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n\nFor example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be a ciphertext message that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n\nTo begin, let's look at the code for a frequency count of the text \"TEST\".\n\nWe'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n\nIt's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 onto the end of our `count_list` 26 times.\n\nWhy can't we just use `+=` for this? We can, but Python is a bit finicky about how it treats lists of numbers. If we wrote `count_list += 0`, we'd get an error (try it below if you'd like). This is because `+=` can only add *lists* to other lists, while `.append` can add numbers.\n\nSince our `count_list` is made up of numbers, we'll have to use the command `count_list.append(0)`. To append any number `n` to a list (call it my_list), the same idea works: we'd write `my_list.append(n)`.\n\nDo you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses in the line \"`for i in range():`\"**","pos":0,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"bb7cf4","input":"Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n\nThe code to add 1 to the 19th entry of `count_list` is:\n\n```\ncount_list[19] += 1\n```\n\nHere, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1. (When operating on single numbers and not lists, `+=` works great!)\n\n**In place of the line \"`## write your code below ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.** Hint: copy-paste the code above, but change 19 to the variable `i`.","pos":6,"state":"done","type":"cell"} -{"cell_type":"markdown","id":"e45b46","input":"Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n\nAs usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n\n**Copy-paste your code from (1.6) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**","pos":14,"state":"done","type":"cell"} -{"id":0,"time":1602616629978,"type":"user"} -{"last_load":1602616630354,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.Frequency_Analysis_rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.Frequency_Analysis_rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 63c60f0..0000000 --- a/Python Modules/*Python Module Rubrics/.Frequency_Analysis_rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,25 +0,0 @@ -{"backend_state":"init","connection_file":"/tmp/xdg-runtime-user/jupyter/kernel-a2a474b9-b812-4663-a797-de1db571431f.json","kernel":"sage-9.1","kernel_error":"","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"cb3a52","input":"","pos":17,"type":"cell"} -{"cell_type":"code","exec_count":10,"id":"38a4b1","input":"# 1.2\n# counts occurences of each letter\nfor x in letter_list:\n for i in range(0,26):\n if x == alphabet[i]:\n ## write your code below ##\n count_list[i] += 1","pos":8,"type":"cell"} -{"cell_type":"code","exec_count":11,"id":"517a40","input":"# 1.3\n# pair each letter of the alphabet with its frequency in a new list\n\n## Write your code here ##\nletter_freq = zip(alphabet,count_list)","pos":10,"type":"cell"} -{"cell_type":"code","exec_count":16,"id":"a96ade","input":"# 1.4\n\n# sort by decreasing order of relative frequency and return the frequencies together with the corresponding ciphertext letters\n\nsorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\nprint sorted_letter_freq","output":{"0":{"name":"stdout","output_type":"stream","text":"[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n"}},"pos":12,"type":"cell"} -{"cell_type":"code","exec_count":17,"id":"0bc076","input":"# 1.5\n## Copy-paste your code here ##\nalphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\nmessage = \"TEST\"\n\nletter_list = []\nfor i in message:\n letter_list.append(i)\n\ncount_list = []\n\n## Edit the line of code below ##\nfor i in range(0,26):\n count_list.append(0)\n\n# counts occurences of each letter\nfor x in letter_list:\n for i in range(0,26):\n if x == alphabet[i]:\n ## write your code below ##\n count_list[i] += 1\n\nletter_freq = zip(alphabet,count_list)\nsorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\nprint(sorted_letter_freq)","output":{"0":{"name":"stdout","output_type":"stream","text":"[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n"}},"pos":14,"type":"cell"} -{"cell_type":"code","exec_count":19,"id":"3a7779","input":"freq_analysis('CABBAGE')","output":{"0":{"name":"stdout","output_type":"stream","text":"[('A', 2), ('B', 2), ('C', 1), ('E', 1), ('G', 1), ('D', 0), ('F', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('S', 0), ('T', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n"}},"pos":20,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"ebff6c","input":"def freq_analysis(message):\n ## copy-paste and edit your code here to define the function ##\n alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n letter_list = []\n for i in message:\n letter_list.append(i)\n count_list = []\n for i in range(0,26):\n count_list.append(0)\n\n # counts occurences of each letter\n for x in letter_list:\n for i in range(0,26):\n if x == alphabet[i]:\n count_list[i] += 1\n letter_freq = zip(alphabet,count_list)\n sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse=True)\n print(sorted_letter_freq)","pos":16,"type":"cell"} -{"cell_type":"code","exec_count":20,"id":"7cb923","input":"freq_analysis('FOUR SCORE AND SEVEN YEARS AGO OUR FATHERS BROUGHT FORTH ON THIS CONTINENT A NEW NATION FOUNDED ON THE PRINCIPLE THAT ALL MEN ARE CREATED EQUAL')","output":{"0":{"name":"stdout","output_type":"stream","text":"[('E', 15), ('N', 13), ('A', 11), ('O', 11), ('T', 11), ('R', 10), ('H', 6), ('I', 5), ('S', 5), ('U', 5), ('C', 4), ('D', 4), ('F', 4), ('L', 4), ('G', 2), ('P', 2), ('B', 1), ('M', 1), ('Q', 1), ('V', 1), ('W', 1), ('Y', 1), ('J', 0), ('K', 0), ('X', 0), ('Z', 0)]\n"}},"pos":21,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"0de465","input":"#Tests\n\n## write your code here ##\nfreq_analysis(\"WHEN IN THE COURSE OF HUMAN EVENTS IT BECOMES NECESSARY FOR ONE PEOPLE TO DISSOLVE THE POLITICAL BANDS WHICH HAVE CONNECTED THEM WITH ANOTHER AND TO ASSUME AMONG THE POWERS OF THE EARTH, THE SEPARATE AND EQUAL STATION TO WHICH THE LAWS OF NATURE AND OF NATURE'S GOD ENTITLE THEM, A DECENT RESPECT TO THE OPINIONS OF MANKIND REQUIRES THAT THEY SHOULD DECLARE THE CAUSES WHICH IMPEL THEM TO THE SEPARATION. WE HOLD THESE TRUTHS TO BE SELF-EVIDENT, THAT ALL MEN ARE CREATED EQUAL, THAT THEY ARE ENDOWED BY THEIR CREATOR WITH CERTAIN UNALIENABLE RIGHTS, THAT AMONG THESE ARE LIFE, LIBERTY AND THE PURSUIT OF HAPPINESS. — THAT TO SECURE THESE RIGHTS, GOVERNMENTS ARE INSTITUTED AMONG MEN, DERIVING THEIR JUST POWERS FROM THE CONSENT OF THE GOVERNED, — THAT WHENEVER ANY FORM OF GOVERNMENT BECOMES DESTRUCTIVE OF THESE ENDS, IT IS THE RIGHT OF THE PEOPLE TO ALTER OR TO ABOLISH IT, AND TO INSTITUTE NEW GOVERNMENT, LAYING ITS FOUNDATION ON SUCH PRINCIPLES AND ORGANIZING ITS POWERS IN SUCH FORM, AS TO THEM SHALL SEEM MOST LIKELY TO EFFECT THEIR SAFETY AND HAPPINESS. PRUDENCE, INDEED, WILL DICTATE THAT GOVERNMENTS LONG ESTABLISHED SHOULD NOT BE CHANGED FOR LIGHT AND TRANSIENT CAUSES; AND ACCORDINGLY ALL EXPERIENCE HATH SHEWN THAT MANKIND ARE MORE DISPOSED TO SUFFER, WHILE EVILS ARE SUFFERABLE THAN TO RIGHT THEMSELVES BY ABOLISHING THE FORMS TO WHICH THEY ARE ACCUSTOMED. BUT WHEN A LONG TRAIN OF ABUSES AND USURPATIONS, PURSUING INVARIABLY THE SAME OBJECT EVINCES A DESIGN TO REDUCE THEM UNDER ABSOLUTE DESPOTISM, IT IS THEIR RIGHT, IT IS THEIR DUTY, TO THROW OFF SUCH GOVERNMENT, AND TO PROVIDE NEW GUARDS FOR THEIR FUTURE SECURITY. — SUCH HAS BEEN THE PATIENT SUFFERANCE OF THESE COLONIES; AND SUCH IS NOW THE NECESSITY WHICH CONSTRAINS THEM TO ALTER THEIR FORMER SYSTEMS OF GOVERNMENT. THE HISTORY OF THE PRESENT KING OF GREAT BRITAIN IS A HISTORY OF REPEATED INJURIES AND USURPATIONS, ALL HAVING IN DIRECT OBJECT THE ESTABLISHMENT OF AN ABSOLUTE TYRANNY OVER THESE STATES. TO PROVE THIS, LET FACTS BE SUBMITTED TO A CANDID WORLD. HE HAS REFUSED HIS ASSENT TO LAWS, THE MOST WHOLESOME AND NECESSARY FOR THE PUBLIC GOOD. HE HAS FORBIDDEN HIS GOVERNORS TO PASS LAWS OF IMMEDIATE AND PRESSING IMPORTANCE, UNLESS SUSPENDED IN THEIR OPERATION TILL HIS ASSENT SHOULD BE OBTAINED; AND WHEN SO SUSPENDED, HE HAS UTTERLY NEGLECTED TO ATTEND TO THEM. HE HAS REFUSED TO PASS OTHER LAWS FOR THE ACCOMMODATION OF LARGE DISTRICTS OF PEOPLE, UNLESS THOSE PEOPLE WOULD RELINQUISH THE RIGHT OF REPRESENTATION IN THE LEGISLATURE, A RIGHT INESTIMABLE TO THEM AND FORMIDABLE TO TYRANTS ONLY. HE HAS CALLED TOGETHER LEGISLATIVE BODIES AT PLACES UNUSUAL, UNCOMFORTABLE, AND DISTANT FROM THE DEPOSITORY OF THEIR PUBLIC RECORDS, FOR THE SOLE PURPOSE OF FATIGUING THEM INTO COMPLIANCE WITH HIS MEASURES. HE HAS DISSOLVED REPRESENTATIVE HOUSES REPEATEDLY, FOR OPPOSING WITH MANLY FIRMNESS HIS INVASIONS ON THE RIGHTS OF THE PEOPLE.HE HAS REFUSED FOR A LONG TIME, AFTER SUCH DISSOLUTIONS, TO CAUSE OTHERS TO BE ELECTED, WHEREBY THE LEGISLATIVE POWERS, INCAPABLE OF ANNIHILATION, HAVE RETURNED TO THE PEOPLE AT LARGE FOR THEIR EXERCISE; THE STATE REMAINING IN THE MEAN TIME EXPOSED TO ALL THE DANGERS OF INVASION FROM WITHOUT, AND CONVULSIONS WITHIN.HE HAS ENDEAVOURED TO PREVENT THE POPULATION OF THESE STATES; FOR THAT PURPOSE OBSTRUCTING THE LAWS FOR NATURALIZATION OF FOREIGNERS; REFUSING TO PASS OTHERS TO ENCOURAGE THEIR MIGRATIONS HITHER, AND RAISING THE CONDITIONS OF NEW APPROPRIATIONS OF LANDS. HE HAS OBSTRUCTED THE ADMINISTRATION OF JUSTICE BY REFUSING HIS ASSENT TO LAWS FOR ESTABLISHING JUDICIARY POWERS. HE HAS MADE JUDGES DEPENDENT ON HIS WILL ALONE FOR THE TENURE OF THEIR OFFICES, AND THE AMOUNT AND PAYMENT OF THEIR SALARIES. HE HAS ERECTED A MULTITUDE OF NEW OFFICES, AND SENT HITHER SWARMS OF OFFICERS TO HARASS OUR PEOPLE AND EAT OUT THEIR SUBSTANCE. HE HAS KEPT AMONG US, IN TIMES OF PEACE, STANDING ARMIES WITHOUT THE CONSENT OF OUR LEGISLATURES. HE HAS AFFECTED TO RENDER THE MILITARY INDEPENDENT OF AND SUPERIOR TO THE CIVIL POWER. HE HAS COMBINED WITH OTHERS TO SUBJECT US TO A JURISDICTION FOREIGN TO OUR CONSTITUTION, AND UNACKNOWLEDGED BY OUR LAWS; GIVING HIS ASSENT TO THEIR ACTS OF PRETENDED LEGISLATION: FOR QUARTERING LARGE BODIES OF ARMED TROOPS AMONG US: FOR PROTECTING THEM, BY A MOCK TRIAL FROM PUNISHMENT FOR ANY MURDERS WHICH THEY SHOULD COMMIT ON THE INHABITANTS OF THESE STATES: FOR CUTTING OFF OUR TRADE WITH ALL PARTS OF THE WORLD:FOR IMPOSING TAXES ON US WITHOUT OUR CONSENT:FOR DEPRIVING US IN MANY CASES, OF THE BENEFIT OF TRIAL BY JURY:FOR TRANSPORTING US BEYOND SEAS TO BE TRIED FOR PRETENDED OFFENCES:FOR ABOLISHING THE FREE SYSTEM OF ENGLISH LAWS IN A NEIGHBOURING PROVINCE, ESTABLISHING THEREIN AN ARBITRARY GOVERNMENT, AND ENLARGING ITS BOUNDARIES SO AS TO RENDER IT AT ONCE AN EXAMPLE AND FIT INSTRUMENT FOR INTRODUCING THE SAME ABSOLUTE RULE INTO THESE COLONIESFOR TAKING AWAY OUR CHARTERS, ABOLISHING OUR MOST VALUABLE LAWS AND ALTERING FUNDAMENTALLY THE FORMS OF OUR GOVERNMENTS:FOR SUSPENDING OUR OWN LEGISLATURES, AND DECLARING THEMSELVES INVESTED WITH POWER TO LEGISLATE FOR US IN ALL CASES WHATSOEVER.HE HAS ABDICATED GOVERNMENT HERE, BY DECLARING US OUT OF HIS PROTECTION AND WAGING WAR AGAINST US.HE HAS PLUNDERED OUR SEAS, RAVAGED OUR COASTS, BURNT OUR TOWNS, AND DESTROYED THE LIVES OF OUR PEOPLE.HE IS AT THIS TIME TRANSPORTING LARGE ARMIES OF FOREIGN MERCENARIES TO COMPLEAT THE WORKS OF DEATH, DESOLATION, AND TYRANNY, ALREADY BEGUN WITH CIRCUMSTANCES OF CRUELTY & PERFIDY SCARCELY PARALLELED IN THE MOST BARBAROUS AGES, AND TOTALLY UNWORTHY THE HEAD OF A CIVILIZED NATION.HE HAS CONSTRAINED OUR FELLOW CITIZENS TAKEN CAPTIVE ON THE HIGH SEAS TO BEAR ARMS AGAINST THEIR COUNTRY, TO BECOME THE EXECUTIONERS OF THEIR FRIENDS AND BRETHREN, OR TO FALL THEMSELVES BY THEIR HANDS.E HAS EXCITED DOMESTIC INSURRECTIONS AMONGST US, AND HAS ENDEAVOURED TO BRING ON THE INHABITANTS OF OUR FRONTIERS, THE MERCILESS INDIAN SAVAGES WHOSE KNOWN RULE OF WARFARE, IS AN UNDISTINGUISHED DESTRUCTION OF ALL AGES, SEXES AND CONDITIONS.IN EVERY STAGE OF THESE OPPRESSIONS WE HAVE PETITIONED FOR REDRESS IN THE MOST HUMBLE TERMS: OUR REPEATED PETITIONS HAVE BEEN ANSWERED ONLY BY REPEATED INJURY. A PRINCE, WHOSE CHARACTER IS THUS MARKED BY EVERY ACT WHICH MAY DEFINE A TYRANT, IS UNFIT TO BE THE RULER OF A FREE PEOPLE.NOR HAVE WE BEEN WANTING IN ATTENTIONS TO OUR BRITISH BRETHREN. WE HAVE WARNED THEM FROM TIME TO TIME OF ATTEMPTS BY THEIR LEGISLATURE TO EXTEND AN UNWARRANTABLE JURISDICTION OVER US. WE HAVE REMINDED THEM OF THE CIRCUMSTANCES OF OUR EMIGRATION AND SETTLEMENT HERE. WE HAVE APPEALED TO THEIR NATIVE JUSTICE AND MAGNANIMITY, AND WE HAVE CONJURED THEM BY THE TIES OF OUR COMMON KINDRED TO DISAVOW THESE USURPATIONS, WHICH WOULD INEVITABLY INTERRUPT OUR CONNECTIONS AND CORRESPONDENCE. THEY TOO HAVE BEEN DEAF TO THE VOICE OF JUSTICE AND OF CONSANGUINITY. WE MUST, THEREFORE, ACQUIESCE IN THE NECESSITY, WHICH DENOUNCES OUR SEPARATION, AND HOLD THEM, AS WE HOLD THE REST OF MANKIND, ENEMIES IN WAR, IN PEACE FRIENDS.WE, THEREFORE, THE REPRESENTATIVES OF THE UNITED STATES OF AMERICA, IN GENERAL CONGRESS, ASSEMBLED, APPEALING TO THE SUPREME JUDGE OF THE WORLD FOR THE RECTITUDE OF OUR INTENTIONS, DO, IN THE NAME, AND BY AUTHORITY OF THE GOOD PEOPLE OF THESE COLONIES, SOLEMNLY PUBLISH AND DECLARE, THAT THESE UNITED COLONIES ARE, AND OF RIGHT OUGHT TO BE FREE AND INDEPENDENT STATES, THAT THEY ARE ABSOLVED FROM ALL ALLEGIANCE TO THE BRITISH CROWN, AND THAT ALL POLITICAL CONNECTION BETWEEN THEM AND THE STATE OF GREAT BRITAIN, IS AND OUGHT TO BE TOTALLY DISSOLVED; AND THAT AS FREE AND INDEPENDENT STATES, THEY HAVE FULL POWER TO LEVY WAR, CONCLUDE PEACE, CONTRACT ALLIANCES, ESTABLISH COMMERCE, AND TO DO ALL OTHER ACTS AND THINGS WHICH INDEPENDENT STATES MAY OF RIGHT DO. — AND FOR THE SUPPORT OF THIS DECLARATION, WITH A FIRM RELIANCE ON THE PROTECTION OF DIVINE PROVIDENCE, WE MUTUALLY PLEDGE TO EACH OTHER OUR LIVES, OUR FORTUNES, AND OUR SACRED HONOR.\")","output":{"0":{"name":"stdout","output_type":"stream","text":"[('E', 859), ('T', 639), ('O', 513), ('N', 483), ('A', 477), ('S', 477), ('I', 449), ('R', 424), ('H', 348), ('D', 252), ('L', 228), ('U', 209), ('C', 184), ('F', 180), ('M', 144), ('P', 138), ('G', 130), ('W', 97), ('B', 95), ('Y', 81), ('V', 74), ('J', 16), ('K', 14), ('X', 9), ('Q', 6), ('Z', 4)]\n"}},"pos":19,"type":"cell"} -{"cell_type":"code","exec_count":7,"id":"11f546","input":"# 1.1\nalphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\nmessage = \"TEST\"\n\ncount_list = []\n\n## Edit the line of code below ##\nfor i in range(0,26):\n count_list.append(0)","pos":2,"scrolled":true,"type":"cell"} -{"cell_type":"code","exec_count":8,"id":"c80e67","input":"# start with a blank list\ncool_list = []\nfor i in message:\n cool_list.append(i)","pos":4,"type":"cell"} -{"cell_type":"code","exec_count":9,"id":"416d0c","input":"## Write your code here ##\nletter_list = []\nfor letter in message:\n letter_list.append(letter)","pos":6,"type":"cell"} -{"cell_type":"markdown","id":"085044","input":"For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about e.g. spaces).\nWe do this by going through our message letter by letter and adding each letter to our list.\nThis is done using the command `.append`. \n\nWhenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n\nIf our list were called `cool_list`, the code to do this would be as follows:","pos":3,"type":"cell"} -{"cell_type":"markdown","id":"1dee1e","input":"Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.4) above in order and run it in order to perform a frequency count on the message `'TEST'`.**","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"3da5f9","input":"## Python Module: Frequency Analysis\n\nFrequency analysis is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n\nFor example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be an encrypted body of text that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n\nTo begin, let's look at the code for a frequency count of the text \"TEST\".\n\nWe'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n\nIt's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 to our `count_list` 26 times.\n\nDo you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses after `range` in the line `for i in range():`**","pos":1,"type":"cell"} -{"cell_type":"markdown","id":"5aacfe","input":"Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)","pos":5,"type":"cell"} -{"cell_type":"markdown","id":"5d0f33","input":"Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes.\n\nThe way Python sorts lists is with the command \n\n```\n{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by])\n```\n\nHere, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n\nIn this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is the first column in the list, since `alphabet` is considered the zeroth column).\n\nBelow, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`.","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"7acd70","input":"Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n\nThe code to add 1 to the 19th entry of `count_list` is:\n\n```\ncount_list[19] += 1\n```\n\nHere, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1.\n\n**In place of the line \"`## write your code here ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.**","pos":7,"type":"cell"} -{"cell_type":"markdown","id":"85d248","input":"**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n\nFor example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`.","pos":18,"type":"cell"} -{"cell_type":"markdown","id":"952b8a","input":"Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n\nAs usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n\n**Copy-paste your code from (1.5) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"c01afa","input":"# Rubric\n\n**Give full credit if students have a function that outputs the letter frequencies either from greatest to least or least to greatest. A recent update to Python changed the code so that the code I outlined should only order from least to greatest.**\n\n- If students don't have a working frequency analysis function, give 20 points for each of the following labeled chunks that has the correct code:\n - (1.1)\n - (1.2)\n - (1.3)\n - (1.4)\n - (1.5)","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"e1ea9c","input":"The code above (once we add a `print(count_list)` command to the end; don't worry about that yet) spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n\n```\n[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n```\n\nwhere the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the 18th spot reflects the count of $T = 18$.\n\nDo you see any problems? \n\nIt's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n\nThe way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n\nSimilarly, we'll get the entries \n\n```\n['B',0], ['C',0], ['D',0], ['E',1],\n```\n\netc.\n\nThe Python command to merge two lists together is `zip(list1, list2)`. **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**.","pos":9,"type":"cell"} -{"id":0,"time":1637269226115,"type":"user"} -{"last_load":1637269225669,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.ShiftDecrypt_rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.ShiftDecrypt_rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 876eb09..0000000 --- a/Python Modules/*Python Module Rubrics/.ShiftDecrypt_rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,46 +0,0 @@ -{"backend_state":"init","connection_file":"/tmp/xdg-runtime-user/jupyter/kernel-2bb4b4ff-8414-48a8-8d5a-52c0b7986281.json","kernel":"sage-9.1","kernel_error":"","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"0a9473","input":"# (1.5)\n# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\n# Start with an empty string of plaintext\n\nplaintext = ''\n\n# Input our ciphertext and key\n\nciphertext = 'DOFCOMWUYMUL'\nkey = 20\n\n# Edit the code below to remove all references to 'D'\n\nfor ciphertext_letter in ciphertext:\n ciphertext_number = alph.find(ciphertext_letter)\n plaintext_number = Mod(ciphertext_number - 20, 26)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\nprint(plaintext)","pos":28,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"20987d","input":"alph(plaintext_number)","pos":16,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"88831b","input":"# (1.5) \nciphertext_number = alph.find(ciphertext_letter)\nplaintext_number = Mod(ciphertext_number - key, 26)\nplaintext_letter = alph(plaintext_number)\nplaintext += plaintext_letter","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"8a50cd","input":"# (1.3) The code below will convert a plaintext number to a plaintext letter.\n\nplaintext_letter = alph(plaintext_number)","pos":18,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"b003a7","input":"# (1.2) Once you edit the code below, it should decrypt instead of encrypt.\n\n# 2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is 3. In other words, we're taking the plaintext number plus the key, mod 26, to get the ciphertext number. \nplaintext_number = Mod(ciphertext_number - key, 26)","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"bda7b5","input":"# (1.4) Edit this code so that it appends plaintext_letter to plaintext\n\nplaintext += plaintext_letter","pos":20,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"d8f3c0","input":"# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\n# Start with an empty string of ciphertext\n\nciphertext = ''\n\n# Carry out the encryption steps\n\n# 1. Convert the plaintext letter to a plaintext number.\n\nplaintext_number = alph.find(letter)\n\n# 2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is 3. In other words, we're taking the plaintext number plus the key, mod 26, to get the ciphertext number. \n\nciphertext_number = Mod(plaintext_number + key, 26)\n\n# 3. Convert the ciphertext number to a ciphertext letter.\n\nciphertext_letter = alph[ciphertext_number]\n\n# 4. Append that letter to our output ciphertext.\n\nciphertext += ciphertext_letter","pos":4,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"6ae0a3","input":"# (1.6)\n# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\n# Start with an empty string of plaintext\n\nplaintext = ''\n\n# Input our ciphertext and key\n\nciphertext = 'DOFCOMWUYMUL'\nkey = 20\n\n# Edit the code below to remove all references to 'D'\n\nfor ciphertext_letter in ciphertext:\n ciphertext_number = alph.find(ciphertext_letter)\n plaintext_number = Mod(ciphertext_number - 20, 26)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter","pos":25,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"69b24f","input":"alph.find('D')","output":{"0":{"data":{"text/plain":"3"},"exec_count":3,"output_type":"execute_result"}},"pos":6,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"b5ba11","input":"# (1.6)\n# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\nplaintext = ''\n\n# Edit the code below to remove all references to specific ciphertext or keys\n\nfor letter in ciphertext:\n ciphertext_number = alph.find(letter)\n plaintext_number = Mod(ciphertext_number - key, 26)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n\nprint(plaintext)","output":{"0":{"name":"stdout","output_type":"stream","text":"JULIUSCAESAR\n"}},"pos":30,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"ea3885","input":"def ShiftDecryptX(ciphertext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n plaintext = ''\n for letter in ciphertext:\n ciphertext_number = alph.find(letter)\n plaintext_number = Mod(ciphertext_number - key, 29)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n print(plaintext)","pos":39,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"49e72f","input":"# Write the code to decrypt your encrypted message here.\n\n# Answer may vary. Example:\nShiftDecryptX('KMLICW', 27)","output":{"0":{"name":"stdout","output_type":"stream","text":"MONKEY\n"}},"pos":41,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"c1ca81","input":"# Define our cipher alphabet as all capital English letters\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n\n# Begin with an empty string of plaintext\n\nplaintext = ''\n\n# Input our ciphertext letter and key\n\nciphertext_letter = 'D'\nkey = 20\n\n# Your code goes below\n\nalph.find(ciphertext_letter)","output":{"0":{"data":{"text/plain":"3"},"exec_count":4,"output_type":"execute_result"}},"pos":8,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"e94152","input":"# (1.7)\ndef ShiftDecrypt(ciphertext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n plaintext = ''\n for letter in ciphertext:\n ciphertext_number = alph.find(letter)\n plaintext_number = Mod(ciphertext_number - key, 26)\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n print(plaintext)","pos":32,"type":"cell"} -{"cell_type":"code","exec_count":5,"id":"c2e000","input":"# (1.1) This step converts a ciphertext letter to a ciphertext number and stores the number\n\nciphertext_number = alph.find(ciphertext_letter)","pos":10,"type":"cell"} -{"cell_type":"code","exec_count":6,"id":"606654","input":"ShiftDecrypt(\"SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ\",7)","output":{"0":{"name":"stdout","output_type":"stream","text":"LIFELIBERTYANDTHEPURSUITOFHAPPINESS\n"}},"pos":34,"type":"cell"} -{"cell_type":"code","exec_count":7,"id":"3e5dba","input":"ShiftDecrypt(\"QPUBUPFT\",27)","output":{"0":{"name":"stdout","output_type":"stream","text":"POTATOES\n"}},"pos":36,"type":"cell"} -{"cell_type":"markdown","id":"00011d","input":"Now, just as before, we want to assign our new plaintext letter to the variable `plaintext_letter`. In order to do so, copy-paste your code from the box above after the equals sign below.","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"097bc1","input":"Great! If your code worked, you should end up with the number $3$. Below, copy-paste your line of code from above after the equals sign in order to assign this $3$ to the variable `ciphertext_number`.","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"0f576d","input":"3. Finally, test your new function by first using your beefed-up `ShiftEncrypt` function from Exercise 2 of that assignment to encrypt a message. Then, in the box below, input the encrypted message and run your beefed-up `ShiftDecrypt` function from Exercise 2 above to decrypt it. Did you get the plaintext you started with? Why or why not?","pos":40,"type":"cell"} -{"cell_type":"markdown","id":"122af4","input":"### Let's do it!\n\nAre you back? Great! Let's try to write a `for` loop that decrypts the entire message 'DOFCOMWUYMUL', which was encrypted with the key $k=20$. \n\nOur goal is to replace the letter 'D' in our code above with a *variable*. Like in algebra, variables can take on many values. So far, we've already seen the variables ``alph``, ``plaintext``, ``key``, and ``ciphertext``. They are placeholders for letters or numbers that can be assigned values, just like the equation $x=3$ assigns the variable $x$ the value $3$.\n\nBelow, I've started you off with the beginning of a `for` loop and the code we used to shift 'D' back by $20$. Edit that code by deleting all references to 'D' and replacing them with the variable ``letter``. Then the `for` loop will cycle through all the letters in the message 'DOFCOMWUYMUL' and shift *all* of them back by $20$. Then click Run on your edited chunk and see what happens. Once you click Run and observe the results, read the text below the chunk.","pos":24,"type":"cell"} -{"cell_type":"markdown","id":"1ca13f","input":"Now, what do we want to do to this number in order to decrypt it? In words (not Sage code), describe this step in the box below. ","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"20e00f","input":"*Convert the ciphertext letter to a ciphertext number.*","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"2a829c","input":"### Undoing step $2$\n\nWe now want to undo step $2$ of the process above. Step $2$ took our plaintext number and added the key, mod $26$, to get our ciphertext number.\n\nNow, we're starting with a ciphertext number and want to go back to a plaintext number. Below, I've recopied the code for step $2$ of the encryption process. Alter the code in order to make it *decrypt* instead of *encrypt*. **Hint**: take the modular arithmetic equation we used to decrypt shift ciphers in class, $P\\equiv C-k\\mod{26}$, and replace $P$ with `plaintext_number`, $C$ with `ciphertext_number`, and $k$ with `key`.","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"4509e5","input":"### Time to print!","pos":26,"type":"cell"} -{"cell_type":"markdown","id":"461018","input":"Now, however, we're starting with ciphertext, given unsurprisingly by the variable `ciphertext`, and we want to *end up with* plaintext. Just like we did above, we'll start with an empty string of plaintext using the command\n\n``plaintext = ''``\n\n(don't worry too much about how this works).\n\nAbove, step $3$ converted our ciphertext numbers to ciphertext letters using the `alph` command. Step $1$ converted letters to numbers using the `alph.find` command. Which command, `alph` or `alph.find`, do we want to use to convert our ciphertext letters to numbers? Write your answer below.","pos":5,"type":"cell"} -{"cell_type":"markdown","id":"466404","input":"# Rubric\n\n- 50 points: student's `ShiftDecrypt` function correctly decrypts `SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ` as `LIFELIBERTYANDTHEPURSUITOFHAPPINESS`.\n- 10 points: in Exercise 1, students correctly decrypt with a shift of $27$ and justify why decrypting with a $-27$ shift is equivalent to decrypting with a $-1$ shift modulo $26$.\n- 40 points: student verifies that running their extended-alphabet `ShiftEncrypt` function on some plaintext of their choice, then running their extended-alphabet `ShiftDecrypt` function on the resulting ciphertext, gives back the initial plaintext.","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"52d1ad","input":"*Shift it back by 20, mod 26*","pos":12,"type":"cell"} -{"cell_type":"markdown","id":"5ab92c","input":"The chunk above should have again spit out the plaintext corresponding to the ciphertext 'DOFCOMWUYMUL'. This is because we've already told Python in the previous section that `ciphertext` is a placeholder for the text 'DOFCOMWUYMUL' and `key` is a placeholder for the number $20$. What if we want to decrypt a different message using a different key? Do we have to write all this code out again, changing the values of the variables `ciphertext` and `key`? Thankfully, no!\n\nTo save us from having to write out all this code anytime we want to decrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to decrypt the message 'AJTQETA' using the key $7$, all we'll have to write is\n\n``ShiftDecrypt('AJTQETA',7)``\n\nJust like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n\nThe function we're dealing with doesn't just have one input, though, it has two: the ciphertext and the key. One of those inputs (the ciphertext) is a word and the other is a number.\n\nRemember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once, and everything in your `for` loop has to be tabbed over once more, so the stuff inside your `for` loop is *double*-tabbed! I\"ll start you off by defining the alphabet and the empty string called `plaintext` like we did above.","pos":31,"type":"cell"} -{"cell_type":"markdown","id":"610aa5","input":"Now, mimic my code in the 'AJTQETA' example above and use your function to decrypt the phrase 'SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ' with a shift of $7$. Yes, it was a lot of work to write the function, but now that we have the function, decryption is so much easier than it would be by hand! (**Hint**: you probably want to copy/paste the ciphertext.)","pos":33,"type":"cell"} -{"cell_type":"markdown","id":"623ae6","input":"Decrypting with a key of $27$ is the same as decrypting with a key of $1$. This is because $27\\equiv 1\\mod{26}$.","pos":37,"type":"cell"} -{"cell_type":"markdown","id":"764c1f","input":"Now, say we're given the ciphertext letter 'D'. Below, I'll start with an empty string of plaintext, then assign the variable `ciphertext_letter` to the letter 'D' and the variable `key` to the value $20$ (don't worry too much about how this works). Below my code, write the code to convert the variable `ciphertext_letter` to a number using the command you wrote above, either `alph` or `alph.find`. Then run your code to see if it works and talk to someone if it doesn't.","pos":7,"type":"cell"} -{"cell_type":"markdown","id":"7b4745","input":"If you edited and ran the code above correctly, *nothing should have happened*. Why not? Well, we didn't actually tell Sage to *show* us the ciphertext.\n\nThis might sound silly. Computer programs and programming languages are very smart in some ways and very dumb in others. To a human, it'd be obvious that, if we asked them to decrypt some ciphertext, they should actually tell us what the decrypted message says. To Python, not so much. We have to explicitly ask using the `print` command.\n\nThe `print` command doesn't actually send anything to a printer. It just prints words, numbers, or letters on the screen.\n\nIn our case, we want to print the plaintext, which we've conveniently assigned to the variable `plaintext`. In the code box below, copy-paste your code from chunk (1.5) above. Then, outside the tabbed section, write the command to print the variable `plaintext`. Then run the chunk and see what happens. You should see the ciphertext resulting from decrypting the word 'DOFCOMWUYMUL' with the key $20$.","pos":27,"type":"cell"} -{"cell_type":"markdown","id":"8a542c","input":"### Undoing step $1$\n\nGreat! We've undone steps $3$ and $2$; now to undo step $1$. When we were encrypting messages, step $1$ was to convert a plaintext letter to a plaintext number. However, when decrypting and after undoing steps $3$ and $2$, we end up with a plaintext *number*. How do we convert it to a plaintext letter? Below, write the code to convert the variable `plaintext_number` from a number to a letter. **Hint**: you're using either `alph` or `alph.find`.","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"8e653a","input":"### Secret extra step: appending our letter to the output plaintext\n\nWe're not quite done yet! Just like we appended our ciphertext letters to the output ciphertext in step 4 of the encryption process, we have to append our output *plain*text letters to the output *plain*text in step 4 of the *de*cryption process.\n\nThe code below was used in the last module to append the variable `ciphertext_letter` to the variable `ciphertext`. Below, edit the code so that it appends the variable `plaintext_letter` to the variable `plaintext` instead.","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"c44303","input":"# Decrypting Shift Ciphers with Known Key\n\n## Decrypting a single letter\n\nIf we know the key, decrypting a letter that was encrypted using a shift cipher just requires undoing the encryption steps. In the last module, we performed the following four steps to encrypt a letter using a shift cipher:\n\n1. Convert the plaintext letter to a plaintext number.\n2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is $3$. In other words, we're taking the plaintext number plus the key, mod $26$, to get the ciphertext number. \n3. Convert the ciphertext number to a ciphertext letter. \n4. Append that letter to our output ciphertext.\n\nIn order to *undo* this process, we'll have to undo each step *backwards*. If you were given a cipheretxt letter (say 'D') and a key (say $20$), what would be your first step if you were trying to decrypt the letter? In words (not Sage code), describe this step in the box below. **Hint**: for time and accuracy reasons, you probably don't want to recite the alphabet backwards by $20$ letters.","pos":1,"type":"cell"} -{"cell_type":"markdown","id":"cf40b2","input":"### Undoing step $3$\n\nEffectively, we're *undoing* step 3 first. Here is the code we used to encrypt a letter (given by the variable `plaintext`) in our previous Sage module. Note that, just like with encryption, we first want to define a cipher alphabet: in this case, all capital English letters.","pos":3,"type":"cell"} -{"cell_type":"markdown","id":"d7f80a","input":"Here, describe whether you got the plaintext you started with and why or why not.","pos":42,"type":"cell"} -{"cell_type":"markdown","id":"e63eb1","input":"### Putting it all together\n\nAwesome! The code we've written so far takes the ciphertext letter 'D', assigns it to the variable `ciphertext_letter`, and does the following:\n\n1. Converts the ciphertext letter to a ciphertext number and stores this number in the variable `ciphertext_number`.\n2. Subtracts the key from the ciphertext number and stores the result in the variable `plaintext_number`.\n3. Converts the plaintext number to a plaintext letter and stores this letter in the variable `plaintext_letter`.\n4. Appends the `plaintext_letter` to the output `plaintext`.\n\nIn the code chunk below, copy the lines of code you wrote marked (1.1), (1.2), (1.3), and (1.4) all in order. This code contains the whole decryption process for a single ciphertext letter!","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"ea0a40","input":"2. Copy and paste the function above (changing its name) and try to change the code so that it decrypts using *the same* larger alphabet you used in the ShiftEncrypt module. Be sure to adjust the modulus accordingly!","pos":38,"type":"cell"} -{"cell_type":"markdown","id":"f6f5a0","input":"## Exercises\n\nNow that you have a function, try answering the following:\n\n1. What do you think happens if you try to *decrypt* use a key that's larger than your alphabet? Try decrypting the message 'QPUBUPFT' with a key of 27 and see! Is the result what you expected? Can you do some modular arithmetic to show why this is the case?","pos":35,"type":"cell"} -{"cell_type":"markdown","id":"f93088","input":"## Decrypting whole words\n\nGreat! You've managed to shift one ciphertext letter to a plaintext letter. However, in order to decrypt messages, we're going to need to shift *multiple* ciphertext letters at once. To do this, we need the magic of ``for`` loops.\n\nYou've already seen ``for`` loops in Codecademy and in the previous module. Basically, the idea is that we want to repeat a task, like shifting letters, over and over again. How many times do we want to repeat the task? Well, once for every letter in our ciphertext. The code to start this ``for`` loop is\n\n``for ciphertext_letter in ciphertext:``\n\nIf you type the above line of code into a code chunk and hit enter, the next line will be tabbed over. Python uses whitespace as a way of managing what's inside a `for` loop and what's not. **Every bit of code you write that's tabbed over under a `for` loop will be run for every single letter of your ciphertext.** \n\nSo what should we write tabbed over inside this `for` loop? I'm glad you asked. Once you've reached this point, try to help others around you until we're all at this point, and we'll talk as a class about what goes inside our `for` loop.","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"faa391","input":"## Creating a Function\n\nNow, when shift ciphers are used in the real world, the ciphertext is almost certain not to be 'DOFCOMWUYMUL', and the key may not be $20$. Instead of this specific ciphertext and key, we want to allow ourselves the freedom to *define* whatever ciphertext and key we want. In other words, we want ``ciphertext`` and ``key`` to be *inputs* to a function.\n\nWe can almost exactly recycle our code from above, where we decrypted 'DOFCOMWUYMUL' with a shift of $20$. However, we'll need to replace any references to specific ciphertext with the variable `ciphertext` and any references to specific numerical keys with the variable `key`.\n\nIn the code box below, remove all references to the ciphertext 'DOFCOMWUYMUL', leaving only references to the variable `ciphertext`, and all references to the number $20$, leaving only references to the variable `key`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below.","pos":29,"type":"cell"} -{"id":0,"time":1632893556215,"type":"user"} -{"last_load":1632924374632,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.ShiftEncrypt_rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.ShiftEncrypt_rubric.ipynb.sage-jupyter2 deleted file mode 100755 index e366b48..0000000 --- a/Python Modules/*Python Module Rubrics/.ShiftEncrypt_rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,55 +0,0 @@ -{"backend_state":"init","kernel":"sage-9.1","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":10,"id":"d7fd08","input":"Mod(3+plaintext_number,26)","output":{"0":{"data":{"text/plain":"15"},"exec_count":10,"output_type":"execute_result"}},"pos":20,"type":"cell"} -{"cell_type":"code","exec_count":12,"id":"c97b35","input":"ciphertext_number = Mod(3+plaintext_number,26)","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":13,"id":"eb3e74","input":"alph[ciphertext_number]","output":{"0":{"data":{"text/plain":"'P'"},"exec_count":13,"output_type":"execute_result"}},"pos":24,"type":"cell"} -{"cell_type":"code","exec_count":14,"id":"6d576c","input":"ciphertext_letter = alph[ciphertext_number]","pos":26,"type":"cell"} -{"cell_type":"code","exec_count":15,"id":"11c417","input":"ciphertext += ciphertext_letter\nciphertext","output":{"0":{"data":{"text/plain":"'P'"},"exec_count":15,"output_type":"execute_result"}},"pos":28,"type":"cell"} -{"cell_type":"code","exec_count":16,"id":"9fd4d0","input":"plaintext = 'MYSECRET'\nciphertext = ''\nkey = 3\n\nfor letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(plaintext_number + 3, 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter","pos":32,"type":"cell"} -{"cell_type":"code","exec_count":17,"id":"bb85ef","input":"print(\"Hamsters!\")","output":{"0":{"name":"stdout","output_type":"stream","text":"Hamsters!\n"}},"pos":34,"type":"cell"} -{"cell_type":"code","exec_count":18,"id":"d7e748","input":"hamsters = 3\nprint hamsters","output":{"0":{"name":"stdout","output_type":"stream","text":"3\n"}},"pos":36,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"912cd6","input":"# Don't change any of the lines beginning with # signs! These are \"comments\" (here used to give instructions) and don't affect what your code is doing.\n# Don't mess with the code below; it just defines our cipher alphabet as all capital English letters. That means our ciphertext and plaintext will both be capital letters. This is a bit different from how we do things in class, but Python works differently.\n\nalph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'","pos":2,"type":"cell"} -{"cell_type":"code","exec_count":20,"id":"743524","input":"plaintext = 'MYSECRET'\nciphertext = ''\nkey = 3\n\nfor letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(plaintext_number + 3, 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\nprint ciphertext","output":{"0":{"name":"stdout","output_type":"stream","text":"PBVHFUHW\n"}},"pos":38,"type":"cell"} -{"cell_type":"code","exec_count":21,"id":"c2fa2d","input":"ciphertext = ''\n\nfor letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(plaintext_number + key, 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\nprint(ciphertext)","output":{"0":{"name":"stdout","output_type":"stream","text":"PBVHFUHW\n"}},"pos":40,"type":"cell"} -{"cell_type":"code","exec_count":22,"id":"46c6a0","input":"def ShiftEncrypt(plaintext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n ciphertext = ''\n for letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(plaintext_number + key, 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\n print(ciphertext)","pos":42,"type":"cell"} -{"cell_type":"code","exec_count":23,"id":"e570b2","input":"ShiftEncrypt('STARGAZER',17)","output":{"0":{"name":"stdout","output_type":"stream","text":"JKRIXRQVI\n"}},"pos":44,"type":"cell"} -{"cell_type":"code","exec_count":24,"id":"2bf1ee","input":"ShiftEncrypt(\"MONKEY\", 27)","output":{"0":{"name":"stdout","output_type":"stream","text":"NPOLFZ\n"}},"pos":46,"type":"cell"} -{"cell_type":"code","exec_count":25,"id":"ff65e5","input":"def ShiftEncryptX(plaintext, key):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n ciphertext = ''\n for letter in plaintext:\n plaintext_number = alph.find(letter)\n ciphertext_number = Mod(plaintext_number + key, 29)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\n print(ciphertext)","pos":49,"type":"cell"} -{"cell_type":"code","exec_count":26,"id":"6ba4ff","input":"ShiftEncryptX(\"MONKEY\",27)","output":{"0":{"name":"stdout","output_type":"stream","text":"KMLICW\n"}},"pos":50,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"17a1c9","input":"plaintext = 'MYSECRET'","pos":4,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"99581e","input":"key = 3","pos":6,"type":"cell"} -{"cell_type":"code","exec_count":5,"id":"965a8f","input":"ciphertext = ''","pos":8,"type":"cell"} -{"cell_type":"code","exec_count":6,"id":"2303f2","input":"alph.find('M')","output":{"0":{"data":{"text/plain":"12"},"exec_count":6,"output_type":"execute_result"}},"pos":10,"type":"cell"} -{"cell_type":"code","exec_count":7,"id":"6d8168","input":"plaintext_number = alph.find('M')","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":8,"id":"e91c22","input":"plaintext_number","output":{"0":{"data":{"text/plain":"12"},"exec_count":8,"output_type":"execute_result"}},"pos":16,"type":"cell"} -{"cell_type":"code","exec_count":9,"id":"dc94fc","input":"Mod(3+12,26)","output":{"0":{"data":{"text/plain":"15"},"exec_count":9,"output_type":"execute_result"}},"pos":18,"type":"cell"} -{"cell_type":"markdown","id":"146534","input":"Let's store this plaintext number $12$ for later. In order to store answers, we'll have to give them names. Let's name this $12$, which is the plaintext number corresponding to the letter 'M'. We'll call it ``plaintext_number`` (no spaces are allowed in Python names).\n\nRecall that naming things in Python is done with the `=` sign. For example, to label the number $4$ with the word `banana`, we'd just write `banana = 4`.\n\nLater, we're going to generalize our code, so instead of just writing `plaintext_number = 12`, we'll remember that the $12$ came from the command `alph.find('M')`. Thus, we'll label `alph_find('M')` with the label `plaintext_number` as follows:","pos":13,"type":"cell"} -{"cell_type":"markdown","id":"16fd04","input":"Now, we want to go through every letter of the plaintext 'MYSECRET' and, one by one, replace these letters with ciphertext letters.\n\nIn other words, for every letter in the plaintext, we want to do the following in order:\n\n1. Convert the plaintext letter to a plaintext number. Sage already has the ability to do this built-in.\n2. To get a ciphertext number, shift the plaintext number up by 3, looping around so that, for example, Z is replaced with C. In other words, we're taking the plaintext number plus $3$, mod $26$, to get the ciphertext number. \n3. Convert the ciphertext number to a ciphertext letter. \n4. Append that letter to our output ciphertext.\n\n## Shifting a Single Letter\n\nThis process can be tricky to understand, so let's go through it with a single letter first. Say we want to encrypt the letter M from 'MYSECRET'. What do we need to do?\n\n1. Convert the plaintext letter to a plaintext number. \n\nSage does this using the function ``alph.find``. Recall that when Python deals with letters, you have to put apostrophes or quotation marks (it doesn't matter which) around them so that Python realizes they're letters. (Technically, Python counts anything within apostrophes or quotes as a \"string\", which is exactly how we want it to treat letters and words.) So to find which number corresponds to the letter M, we'd write:","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"1b4e9b","input":"2. Finally, copy and paste the function above (changing the function's name) and try to change the code so that it encrypts using a larger alphabet of your choice. For example, you could add the special characters ~!? to your alphabet. Be sure to adjust the modulus accordingly!","pos":48,"type":"cell"} -{"cell_type":"markdown","id":"1e2943","input":"Now, mimic my code in the 'POTATO' example above and use your function to encrypt the word 'STARGAZER' with a shift of $17$. Yes, it was a lot of work to write the function, but now that we have the function, encryption is so much easier than it would be by hand!","pos":43,"type":"cell"} -{"cell_type":"markdown","id":"1f2e67","input":"In the box below, copy-paste your code from above, but this time label the resulting ciphertext letter with the variable `ciphertext_letter` so we can easily refer to it in the future.","pos":25,"type":"cell"} -{"cell_type":"markdown","id":"20ffb6","input":"If you type the above line of code into a code chunk and hit enter, the next line will be tabbed over. Python uses whitespace as a way of managing what's inside a `for` loop and what's not. **Everything you write that's tabbed over will be done for every single letter of your plaintext.** \n\nSo what should we write tabbed over inside this `for` loop? I'm glad you asked. Once you've reached this point, try to help others around you until we're all at this point, and we'll talk as a class about what goes inside our `for` loop.","pos":30,"type":"cell"} -{"cell_type":"markdown","id":"23735d","input":"# Shift Ciphers in Sage\n\n## Welcome!\n\nWelcome to your first Sage module for the course! Sage is a bunch of math-centric enhancements to the Python programming language. \n\nDoes that mean you're expected to learn how to program in this course? Not at all! While you're welcome to play around and try to extend your code if you have prior programming experience (come talk to me about your plans if this is the case), most of what you'll be doing involves \"thoughtful copy-pasting\" of existing code.\n\nWhat is \"thoughtful copy/paste\"? When coding is new to people, it's almost impossible to type a line of code that will run without error. Why not find some code that you know will execute and modify it slightly? It's in that modification that one needs to be thoughtful. What do you need to change and why? The goal for this course is that you'll come out with a little more knowledge of how to tweak a single bit of code to suit your needs.\n\nDoes this sound like cheating? It isn't a cop-out. It's helping everyone get to the point where Sage makes sense and will give results. In fact, you have some programming background and are interested in doing more with R, there are countless online resources you can visit to augment your learning. (The rest of the free Codecademy Python course is a good start.)\n\n## What's the point?\n\nSo why are we using programming in a cryptography course? Frankly, because no one does cryptography anymore with pen and paper. While this may have been possible in Julius Caesar's time, nowadays cryptography is conducted almost exclusively on computers, by computer programs. In fact, by the end of this course, we'll be doing cryptography this is *literally impossible* to do by hand. This type of cryptography (RSA encryption) keeps credit card info safe online and is one of the most commonly used computer programs today.\n\nEven for older encryption systems like shift ciphers, it's still an enormous time-saver to use a computer to encrypt our messages. My goal in this course is to give you more time to focus on concepts than on the arithmetic and simple computations you need to encrypt shift ciphers. Once you understand the basics of how a cipher works, shifting repetitive tasks to a computer helps you focus on the broader concepts underlying each type of encryption.\n\n## Setting Up\n\nTo this end, our goal is to play around with a small program that will encrypt text using a shift cipher. \n\nWe want to be able to input any plaintext we want and the desired shift. The program should then spit out the ciphertext.\n\nFirst, we'll do an example, encoding the message \"MYSECRET\" using a shift of 3, like the classical Caesar cipher. You'll then use this example to define a function.","pos":1,"type":"cell"} -{"cell_type":"markdown","id":"31285d","input":"## Exercises\n\nNow that you have a function, try answering the following:\n\n1. What do you think happens if you try to use a key that's larger than your alphabet? Try encoding a message with a shift of 27 and see! Is the result what you expected? Can you do some modular arithmetic to show why this is the case?","pos":45,"type":"cell"} -{"cell_type":"markdown","id":"3ba123","input":"Now back to shift ciphers. We want to print the ciphertext, which we've conveniently assigned to the variable `ciphertext`. In the code box below, outside the tabbed section, write the command to print the variable `ciphertext`. Then run the chunk and see what happens. You should see the ciphertext resulting from encrypting the word 'MYSECRET' with the key $3$.","pos":37,"type":"cell"} -{"cell_type":"markdown","id":"480bf6","input":"3. Convert the ciphertext number to a ciphertext letter.\n\nThankfully, Sage also has the ability to convert numbers to letters built-in. The command is ``alph``. So, for example, to convert the number 21 to a letter, we'd write ``alph[21]``.\n\nBelow, write the code to convert our ciphertext number (which we conveniently labeled `ciphertext_number`) to a letter. In other words, replace the $21$ above with the variable `ciphertext_number`. If it doesn't do what you expect, talk to a group member or your instructor.\n\nIt's useful to test code like this, doing a \"sanity check\". If you ask Python to compute $4+3\\mod{26}$ and it spits out $1$, you know something probably went wrong. Then you can go back to your code and try to fix it.","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"4da8dc","input":"Click on the code chunk above. Now, click on the button \"Run\" in the toolbar just below the \"File, Edit, View\" menu. What happens? Is this what you'd expect? Write your answer in the empty text box below this line.","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"5ecf0b","input":"Here's our next step:\n\n2. To get a ciphertext number, shift the plaintext number up by 3, looping around so that, for example, Z is replaced with C. In other words, we're taking the plaintext number plus 3, mod 26, to get the ciphertext number. \n\nSage also has this ability built-in. For example, to do 24 plus 3 mod 26, the code is ``Mod(24+3,26)``. The first thing after the parentheses is the number we want to reduce mod 26. The second number is the modulus. This gives us a ciphertext number.\n\nBelow, write the code to add $3$ to the number $12$ mod $26$. In other words, we want to do $12+3\\mod{26}$. Then run your code. If it doesn't do what you expect, talk to a group member or your instructor.","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"6874e1","input":"Our first step is to write the plaintext message we want to encrypt and label it with the variable ``plaintext``. After we type the line below, every time we write ``plaintext``, Python will replace it with ``'MYSECRET'``.","pos":3,"type":"cell"} -{"cell_type":"markdown","id":"6cc852","input":"## Shifting Whole Words\n\nGreat! You've managed to shift one plaintext letter to a ciphertext letter. However, in order to encrypt messages, we're going to need to shift *multiple* plaintext letters at once. To do this, we need the magic of ``for`` loops.\n\nYou've already seen ``for`` loops in Codecademy. Basically, the idea is that we want to repeat a task, like shifting letters, over and over again. How many times do we want to repeat the task? Well, once for every letter in our plaintext. The code to start this ``for`` loop is\n\n``for letter in plaintext:``","pos":29,"type":"cell"} -{"cell_type":"markdown","id":"6e6b09","input":"Finally, just like we labeled $12$ with `plaintext_number`, we'll label the $15$ with `ciphertext_number`. Copy your code from the box above and paste it after the equals sign in the box below.","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"70460c","input":"The chunk above should have again spit out the ciphertext corresponding to the plaintext 'MYSECRET'. This is because we've already told Python in the previous section that `plaintext` is a placeholder for the text 'MYSECRET' and `key` is a placeholder for the number $3$. What if we want to encrypt a different message using a different key? Do we have to write all this code out again, changing the values of the variables `plaintext` and `key`? Thankfully, no!\n\nTo save us from having to write out all this code anytime we want to encrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to encrypt the message 'POTATO' using the key $7$, all we'll have to write is\n\n``ShiftEncrypt('POTATO',7)``\n\nJust like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n\nThe function we're dealing with doesn't just have one input, though, it has two: the plaintext and the key. One of those inputs (the plaintext) is a word and the other is a number.\n\nRemember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once, and everything in your `for` loop has to be tabbed over once more, so the stuff inside your `for` loop is *double*-tabbed! I\"ll start you off by defining the alphabet and the empty string called `ciphertext` like we did above.","pos":41,"type":"cell"} -{"cell_type":"markdown","id":"786326","input":"Because we'll be generalizing this code in a bit, let's replace that $12$ in your code above with the variable `plaintext_number`. In the box below, copy your code from above, but delete the $12$ and write `plaintext_number` in its place. (This will be useful later.)","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"9b8fa1","input":"The alphabet \"rolls over\" or \"starts over\" again. For example, shifting by 27 is the same as shifting by 1.","pos":47,"type":"cell"} -{"cell_type":"markdown","id":"a63ba3","input":"Seems pretty straightforward, right? Anything you put in the parentheses after `print` gets printed. Remember that if you want to print words, you have to enclose those words in apostrophes or quotation marks. However, to print a *variable*, you don't need the quotations. For example, if I had a variable `hamsters` which I set equal to $3$, then the command `print(hamsters)` should spit out the number $3$. \n\nGive it a try! In the chunk below, label the number $3$ with the variable `hamsters`. Then tell Sage to `print` the variable `hamsters`. If you don't get a $3$ out, recheck your code and/or talk to someone.","pos":35,"type":"cell"} -{"cell_type":"markdown","id":"a9b4ae","input":"## Creating a Function\n\nNow, when shift ciphers are used in the real world, the plaintext is almost certain not to be 'MYSECRET', and the key may not be $3$. Instead of this specific plaintext and key, we want to allow ourselves the freedom to *define* whatever plaintext and key we want. In other words, we want ``plaintext`` and ``key`` to be *variables*.\n\nWe can almost exactly recycle our code from above, where we encrypted 'MYSECRET' with a shift of $3$. However, we'll need to replace any references to specific plaintext with the variable `plaintext` and any references to specific numerical keys with the variable `key`. \n\nIn the code box below, remove all references to the plaintext 'MYSECRET', leaving only references to the variable `plaintext`, and all references to the number $3$, leaving only references to the variable `key`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below.","pos":39,"type":"cell"} -{"cell_type":"markdown","id":"aac054","input":"4. Append that letter to our output ciphertext.\n\nRemember that blank word we called ``ciphertext`` above? Here's where it comes in. We've converted the letter M to a number, shifted the number over by $3$, then converted the result back to a letter. If your code worked correctly, the resulting ciphertext letter should be P. (If you didn't get P, try looking over your code above again or asking someone.)\n\nWe now want to store that P as the first letter of our ciphertext. Then we'll add other ciphertext letters one by one until our ciphertext is complete.\n\nIn Python and Sage, adding things one by one is called *appending*. For example, the command to append the letter Q to the variable ``weirdletters`` is ``weirdletters += 'Q'``. The logic behind the `+=` is that we're first adding (`+`-ing) `Q` to the variable `weirdletters`, then we're *redefining* `weirdletters` to be itself plus `Q`. (Re)defining variables in Python is done with `=` signs. So together, we're doing both a `+` and an `=`, hence `+=`. (Don't worry, you won't be required to memorize this; you can always come back to this worksheet to remind yourself.)\n\nBelow, write the code to append `ciphertext_letter` to the variable `ciphertext`. Then, in the next line, test your code by just writing the word ``ciphertext``. Sage should output `'P'` if your code works correctly.","pos":27,"type":"cell"} -{"cell_type":"markdown","id":"ac5d99","input":"### Let's do it!\n\nAre you back? Great! Let's try to write a `for` loop that encrypts the entire message 'MYSECRET' with a shift of $3$. \n\nOur goal is to replace the letter 'M' in our code above with a *variable*. Like in algebra, variables can take on many values. So far, we've already seen the variables ``alph``, ``plaintext``, ``key``, and ``ciphertext``. They are placeholders for letters or numbers that can be assigned values, just like the equation $x=3$ assigns the variable $x$ the value $3$.\n\nBelow, I've started you off with the beginning of a `for` loop and the code we used to shift 'M' by $3$. There's an extra line at the bottom of the for loop which you don't need to worry about for now. Edit that code by deleting all references to 'M' and replacing them with the variable ``letter``. Then the `for` loop will cycle through all the letters in the message 'MYSECRET' and shift *all* of them by $3$. Then click Run on your edited chunk and see what happens. Once you click Run and observe the results, read the text below the chunk.","pos":31,"type":"cell"} -{"cell_type":"markdown","id":"bccce5","input":"Now, a shift of 27 really is different from a shift of anything less than 27.","pos":51,"type":"cell"} -{"cell_type":"markdown","id":"c34fc7","input":"Below, write ``plaintext_number`` in the code box, click Run, and verify that Sage spits out the number $12$.","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"d38a92","input":"We would expect this because the letter M corresponds to the number 12.","pos":12,"type":"cell"} -{"cell_type":"markdown","id":"df50ac","input":"If you edited and ran the code above correctly, *nothing should have happened*. Why not? Well, we didn't actually tell Sage to *show* us the ciphertext.\n\nThis might sound silly. Computer programs and programming languages are very smart in some ways and very dumb in others. To a human, it'd be obvious that, if we asked them to convert plaintext to ciphertext, they should actually tell us what the ciphertext is. To Sage, not so much. We have to explicitly ask using the `print` command.\n\nThe `print` command doesn't actually send anything to a printer. It just prints words, numbers, or letters on the screen. For example, see what happens when you run the code chunk below.","pos":33,"type":"cell"} -{"cell_type":"markdown","id":"e57618","input":"# Rubric:\n\n- 50 points: `ShiftEncrypt` function encrypts `stargazer` as `JKRIXRQVI`\n- 35 points: Student writes a working function in Exercise 2 that correctly encrypts their chosen plaintext in Exercise 3.\n- 15 points: Student justifies why a shift of 27 is equivalent to a shift of 1 in a 26-letter alphabet in Exercise 1.","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"ed518c","input":"OK, now here's the tricky part. How do we actually shift every single letter of the plaintext ``'MYSECRET'`` over by 3? \n\nWe'll do it one letter at a time using a \"for loop\" (remember these from your Intro to Python on Codecademy?).\n\nFor weird reasons that aren't too important, we'll start with an empty ciphertext message and use a for loop to add ciphertext letters to it, one by one.\n\nDefine the variable ``ciphertext`` to be an empty string of letters. This empty string is written as ``''``, two apostrophes with nothing (our empty word) between them.","pos":7,"type":"cell"} -{"cell_type":"markdown","id":"fd3f56","input":"Next, we define the key. In this case, the key is the number of letters to the right we want to shift. (Note that negative keys correspond to left shifts.) As an example, let's use the classical Caesar cipher, which has a right shift of 3 letters. From now on, whenever we type the word ``key``, Python will replace it with the number 3.","pos":5,"type":"cell"} -{"id":0,"time":1632891703708,"type":"user"} -{"last_load":1632891703953,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.VigenereEncrypt-1.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.VigenereEncrypt-1.ipynb.sage-jupyter2 deleted file mode 100755 index 101971c..0000000 --- a/Python Modules/*Python Module Rubrics/.VigenereEncrypt-1.ipynb.sage-jupyter2 +++ /dev/null @@ -1,48 +0,0 @@ -{"backend_state":"init","kernel":"sage-9.1","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.7.3"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"094564","input":"key_numbers = alph.find(keyword)","pos":7,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"5186bd","input":"Answer here","pos":28,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"5b9010","input":"keyword[0]","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"5d50b4","input":"(1.3)\nplaintext_numbers = [alph.find(i) for i in plaintext]","pos":26,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"67b1c1","input":"","pos":40,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"721a52","input":"","pos":44,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"729289","input":"","pos":35,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"7d6208","input":"(1.4)\n\nciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)","pos":30,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"803920","input":"ciphertext = ''","pos":24,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"90fea5","input":"","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"9d91dd","input":"","pos":37,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"a89b5f","input":"def VigenereDecrypt(ciphertext, keyword):\n ","pos":42,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"e30762","input":"Mod(key_number + plaintext_number, 26)","pos":20,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"fdc767","input":"key_length = len(keyword)","pos":18,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"db2bf3","input":"alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'","pos":1,"type":"cell"} -{"cell_type":"code","exec_count":2,"id":"0aabe7","input":"def VigenereEncrypt(plaintext, keyword):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n ciphertext = ''\n plaintext_numbers = [alph.find(i) for i in plaintext]\n key_numbers = [alph.find(i) for i in keyword]\n for i in range(len(plaintext_numbers)):\n ciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)\n ciphertext_letter = alph[ciphertext_number]\n ciphertext += ciphertext_letter\n print ciphertext","pos":33,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"070991","input":"plaintext_number = alph.find(letter)","pos":3,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"07c857","input":"len('SUPERCALIFRAGILISTICEXPIALIDOCIOUS')","output":{"0":{"data":{"text/plain":"34"},"exec_count":4,"output_type":"execute_result"}},"pos":13,"type":"cell"} -{"cell_type":"markdown","id":"0e5898","input":"Vigenère cycles between shifts in the following way. \n\n1. First off, the keyword is spelled out above the message, and repeated over and over again so that each letter in the message is associated with a letter from the keyword: \n
\nPlaintext: d i v e r t t r o o p s t o e a s t r i d g e\nKeyword:   W H I T E W H I T E W H I T E W H I T E W H I\n
\n2. To encrypt the first letter, we note that the plaintext 'd' lines up with the keyword 'W'. This means that we'll shift the 'd' forward by the amount encoded by 'W'.\n\nWhat does W correspond to in our letter-to-number chart, and what would be the result of shifting a 'd' forward by that number?","pos":8,"type":"cell"} -{"cell_type":"markdown","id":"14d858","input":"Now, we want to tell Python to repeat the keyword numbers over and over again under the plaintext numbers. For example, if the keyword is \"NICE\" and the plaintext is \"FIREFIGHTER\", we'd do the following:\n\n1. Convert both to numbers like you did above:\n
\nPlaintext:\n  \n  F  I  R  E  F  I  G  H  T  E  R\n  5  8  17 4  5  8  6  7  19 4  17\n\nKey:\n\n  N  I  C  E  N  I  C  E  N  I  C\n  13 8  2  4  13 8  2  4  13 8  2\n
\n\n2. Repeat the key over and over again under the plaintext, then add corresponding key letters to corresponding plaintext letters:\n\n
\nPlaintext:\n  \n  F  I  R  E  F  I  G  H  T  E  R\n  5  8  17 4  5  8  6  7  19 4  17\n\nKey:\n\n  N  I  C  E  N  I  C  E  N  I  C\n+ 13 8  2  4  13 8  2  4  13 8  2\n  ----------\n  18 16 19 8  18 16 8  11 ...\n  \n
\n\nHow do we tell Python to do this? Well, note that we're adding the first letter of the keyword to the first, fifth, and ninth letters of the plaintext (F, F, T). The length of the keyword here is 4. What time do 1, 5, and 9 all represent on a 4-hour clock?","pos":27,"type":"cell"} -{"cell_type":"markdown","id":"187640","input":"Now, we want to do this for every plaintext letter and the corresponding keyword letter using a `for` loop. Here's a shortcut: the code\n\n
\n(1.2)\nkey_numbers = [alph.find(i) for i in keyword]\n
\n\nturns every letter in the keyword into a number and stores the entire result in the string `key_numbers`. So, for example, if the keyword was \"HI\", `key_numbers` would be `[7, 8]` because $H=7$ and $I=8$ in our letter-to-number chart.\n\nBelow, write the code to convert the entire plaintext to numbers and call the result `plaintext_numbers` (mimic the `key_numbers` code above but change the names).","pos":25,"type":"cell"} -{"cell_type":"markdown","id":"2b4387","input":"","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"330dc1","input":"Continuing our steps for enciphering using Vigenere, the next step is to add the amount of the keyword shift to the plaintext, just as you did with the plaintext 'd' and 'i' in \"divert troops to east ridge\".\n\nYou've already written the code to convert both the plaintext to a number (`plaintext_number`) and the keyword to numbers (`key_number`). Below, write the code to add `key_number` to `plaintext_number` $\\mod{26}$ (but **don't run it**).","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"4294d4","input":"3. Encrypt a reasonably-long message using a key of length 2 below. Then share the ciphertext with a partner at your table and see if they can break it!","pos":39,"type":"cell"} -{"cell_type":"markdown","id":"45c029","input":"The genius of Vigenère is that it uses a *keyword* to cycle between **multiple** shifts, so that a Vigenère cipher is actually multiple shift ciphers that we cycle through (like you cycled through two shifts in your reading question). Any idea how we could use a keyword to encode shifts? Write your answer below.","pos":4,"type":"cell"} -{"cell_type":"markdown","id":"47a376","input":"4. Write a Vigenère **decryption** function by reversing the roles of ciphertext and plaintext in the chunk above where you defined the `VigenereEncrypt` function and changing only one other symbol in the code.","pos":41,"type":"cell"} -{"cell_type":"markdown","id":"48cc44","input":"","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"58f368","input":"OK, we're ready! Copy-paste lines (1.1), (1.2), and (1.3) of code in the chunk below. Below those, copy-paste the beginning of the `for` loop. Finally, tabbed over underneath the `for` command, copy-paste line (1.4) of code. Finally, still underneath the `for` loop, add code to convert `ciphertext_number` back to `ciphertext_letter` and append the result to the end of the string `ciphertext`. Then, outside the loop, have Python print the ciphertext.","pos":32,"type":"cell"} -{"cell_type":"markdown","id":"59b5b4","input":"# Vigenère Encryption\n\nAll of the ciphers we've seen up to this point have been **monoalphabetic substitution ciphers**, meaning they use only one *cipher alphabet* (way of assigning a given plaintext letter to a ciphertext letter). Today, we'll work with a **polyalphabetic substitution cipher** for the first time, where (for example) a plaintext $e$ could be enciphered either as a ciphertext $O$ or a ciphertext $A$.\n\nAs usual, we'll start by telling Python that we're working with capital English letters. Run the chunk below to do this:","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"6875db","input":"As before, our first step is to take a given plaintext letter and convert it to a number. Do you remember what code does this? Copy/paste the code from your `ShiftEncrypt` function that changes plaintext letters to plaintext numbers and labels the number `plaintext_number`. **Don't run the code yet.**","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"6e4b41","input":"OK, we're ready to encipher a single plaintext letter! We want to perform the following steps:\n\n1. Define `alph` to be the capital English alphabet.\n2. Assign the length of the variable `keyword` to the variable `key_length`.\n3. Start with an empty string of ciphertext.\n4. Convert the first letter of the string `plaintext` to a number and call the result `plaintext_number`.\n5. Convert the first letter of the string `keyword` to a number and call the result `key_number`.\n6. Add the `key_number` to the `plaintext_number`, mod $26$, and call the result `ciphertext_number`.\n7. Convert the `ciphertext_number` back to a `ciphertext_letter`.\n8. Add `ciphertext_number` to the string `ciphertext`.\n\nAlmost all these steps are things we've done before in previous modules (e.g., converting letters to numbers and vice versa). Below, write the code to label the empty string `''` with the name `ciphertext`.","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"6f5d7e","input":"So to figure out what key letter to add to a given plaintext letter, we just reduce the position of the plaintext letter modulo the key letter! For example, since 'I' is the sixth letter of 'FIREFIGHTER', we'd add the \n\n$$\n6\\mod{4} \\equiv 2\\text{nd}\n$$\n\nletter of the key to 'I'.\n\nBelow, I'll write the code to do this to the $i$th letter of `plaintext_numbers`, reduce mod 26, and label the result `ciphertext_number`. (Don't run it yet.)","pos":29,"type":"cell"} -{"cell_type":"markdown","id":"7a306a","input":"5. Test your Vigenère decryption function by using it to decrypt your ciphertext from Exercise 1.","pos":43,"type":"cell"} -{"cell_type":"markdown","id":"7beda5","input":"Just like we converted the plaintext to numbers, we need to convert the key to numbers as well. Below, write the code that would convert the variable `keyword` to numbers and label it `key_numbers`.","pos":6,"type":"cell"} -{"cell_type":"markdown","id":"92bdc2","input":"","pos":16,"type":"cell"} -{"cell_type":"markdown","id":"930c99","input":"2. What do you think would happen if you encrypted a Vigenère message using a key with only one letter (e.g. 'B')? Try encrypting the same message from Exercise 1 with the keyword 'B'. What happened? How secure is this cipher?","pos":36,"type":"cell"} -{"cell_type":"markdown","id":"a5fc99","input":"Similarly, since the plaintext 'i' aligns with the keyword 'H', we want to shift the 'i' forward by the amount encoded by the 'H'. What is that shift, and what is the result of shifting 'i' forward by this amount?","pos":10,"type":"cell"} -{"cell_type":"markdown","id":"a8419f","input":"Now, we want to start with an empty string of ciphertext (`''`) and add the corresponding keyword number to every plaintext number. Since we're repeating the step of adding the key letter to the plaintext letter for every letter in the plaintext, we'll need to use a `for` loop!\n\nRemember how we used code like `alph[3]` to find the third letter in the alphabet? That code really treated `alph` as a string and searched for the third character (i.e., letter) in the string, then output that letter. \n\nHow do you think we would output the zeroth (remember Python lists start at zero) letter in the string `keyword`? Write that code below (don't run it):","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"b2336b","input":"","pos":5,"type":"cell"} -{"cell_type":"markdown","id":"b98b6a","input":"Explain what happened here.","pos":38,"type":"cell"} -{"cell_type":"markdown","id":"c36914","input":"We want to do the process in chunk (1.4) to every letter of the plaintext. This requires us to use a for loop that begins\n\n``\nfor i in range(len(plaintext_numbers)):\n``\n\nLet's break this down. The string `plaintext_numbers` is a list of numbers. Its length is the same as the length of the plaintext, one plaintext number for every plaintext letter. \n\nThis `for` loop will start with the zeroth (remember all Python lists start at 0) plaintext number, then move on to the first, then the second, and so on until it reaches the length of the plaintext. This is exactly what we want to do in order to encrypt a message!","pos":31,"type":"cell"} -{"cell_type":"markdown","id":"c48b5f","input":"Finally, we'll assign the length of our `keyword` to the variable `key_length`. Write the code to output the length of the variable `keyword` and assign it to the name `key_length` using code below (don't run it):","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"dbb394","input":"Were the outputs of the `len` functions above what you expected? Why or why not?","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"dc12b1","input":"## Exercises\n\n1. Test your shiny new function by encrypting two or three lines of lyrics by one of your favorite artists using the keyword 'MUSIC'.","pos":34,"type":"cell"} -{"cell_type":"markdown","id":"df1224","input":"Since the key is repeated over and over again under the plaintext, it's important that we know the length of the keyword. \n\nIn Python, the code to output the length of a string (such as a keyword) is `len(string)`. For example, to find the length of the word \"ALLIGATOR\", we'd type\n\n
\nlen('ALLIGATOR')\n
\n\nBelow, write the code to find the length of the word \"SUPERCALIFRAGILISTICEXPIALIDOCIOUS\". In the second code chunk below, write the code to find the length of the variable `alph`, which we've assigned to the English alphabet.","pos":12,"type":"cell"} -{"id":0,"time":1635278727738,"type":"user"} -{"last_load":1635278728729,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.VigenereEncrypt-Rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.VigenereEncrypt-Rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 0e23118..0000000 --- a/Python Modules/*Python Module Rubrics/.VigenereEncrypt-Rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,48 +0,0 @@ -{"backend_state":"init","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":0},"metadata":{"language_info":{"codemirror_mode":{"name":"ipython","version":2},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython2","version":"2.7.15"}},"trust":true,"type":"settings"} -{"cell_type":"code","exec_count":0,"id":"0bd0ca","input":"(1.4)\n\nciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)","pos":30,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"116de6","input":"","pos":7,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"13eade","input":"","pos":20,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"2fd5ae","input":"(1.3)\n","pos":26,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"304a73","input":"(1.1)\n","pos":18,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"6cbdb9","input":"(1.1)\n","pos":24,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"7bab9a","input":"","pos":13,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"84147f","input":"","pos":3,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"af8906","input":"","pos":14,"type":"cell"} -{"cell_type":"code","exec_count":0,"id":"e84e42","input":"","pos":22,"type":"cell"} -{"cell_type":"code","exec_count":1,"id":"21afc7","input":"alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'","pos":1,"type":"cell"} -{"cell_type":"code","exec_count":10,"id":"492e27","input":"# Define a Vigenere decryption function\ndef VigenereDecrypt(ciphertext, keyword):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n key_length = len(keyword)\n# Convert the key and ciphertext from letters to numbers\n key_numbers = [alph.find(i) for i in keyword]\n ciphertext_numbers = [alph.find(i) for i in ciphertext]\n# Start with an empty string of plaintext\n plaintext = ''\n# Write the key over and over again underneath the ciphertext, then subtract the key from the ciphertext and reduce modulo 26. Finally, convert the plaintext numbers to letters and return the result.\n for i in range(len(ciphertext_numbers)):\n plaintext_number = (ciphertext_numbers[i] - key_numbers[i % key_length]) % 26\n plaintext_letter = alph[plaintext_number]\n plaintext += plaintext_letter\n print plaintext","pos":42,"type":"cell"} -{"cell_type":"code","exec_count":11,"id":"3b3512","input":"VigenereDecrypt('RLALCKZJQFMSYWVFUYMVPIOVQZZJQFMS', \"MUSIC\")","output":{"0":{"name":"stdout","output_type":"stream","text":"FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\n"}},"pos":44,"type":"cell"} -{"cell_type":"code","exec_count":17,"id":"edf006","input":"VigenereEncrypt(\"FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\", \"MUSIC\")","output":{"0":{"name":"stdout","output_type":"stream","text":"RLALCKZJQFMSYWVFUYMVPIOVQZZJQFMS\n"}},"pos":35,"type":"cell"} -{"cell_type":"code","exec_count":18,"id":"884973","input":"VigenereEncrypt(\"FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\", \"B\")","output":{"0":{"name":"stdout","output_type":"stream","text":"GSJEBZGSJEBZHPUUBHFUEPXOPOGSJEBZ\n"}},"pos":37,"type":"cell"} -{"cell_type":"code","exec_count":3,"id":"9f61ae","input":"VigenereEncrypt('THIS IS AN EXAMPLE OF A VIGENERE ENCRYPTED MESSAGE', 'OK')","output":{"0":{"name":"stdout","output_type":"stream","text":"HRWCNSGJOXNOLKAZZONYTJOJJSUOBOFONOBMFIDDSNNWSCGKUO\n"}},"pos":40,"type":"cell"} -{"cell_type":"code","exec_count":4,"id":"d79e81","input":"# Define a Vigenere encryption function\ndef VigenereEncrypt(plaintext, keyword):\n alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n key_length = len(keyword)\n# Convert the key and plaintext from letters to numbers\n key_numbers = [alph.find(i) for i in keyword]\n plaintext_numbers = [alph.find(i) for i in plaintext]\n# Start with an empty string of ciphertext\n ciphertext = ''\n# Write the key over and over again underneath the plaintext, then add the two together and reduce modulo 26. Finally, convert the ciphertext numbers to letters and return the result.\n for i in range(len(plaintext_numbers)):\n ciphertext_number = (plaintext_numbers[i] + key_numbers[i % key_length]) % 26\n ciphertext_letter = alph[ciphertext_ ciphertext += ciphertext_letter\n print ciphertext","pos":33,"type":"cell"} -{"cell_type":"markdown","id":"05c36e","input":"We want to do the process in chunk (1.4) to every letter of the plaintext. This requires us to use a for loop that begins\n\n``\nfor i in range(len(plaintext_numbers)):\n``\n\nLet's break this down. The string `plaintext_numbers` is a list of numbers. Its length is the same as the length of the plaintext, one plaintext number for every plaintext letter. \n\nThis `for` loop will start with the zeroth (remember all Python lists start at 0) plaintext number, then move on to the first, then the second, and so on until it reaches the length of the plaintext. This is exactly what we want to do in order to encrypt a message!","pos":31,"type":"cell"} -{"cell_type":"markdown","id":"073d1a","input":"As before, our first step is to take a given plaintext letter and convert it to a number. Do you remember what code does this? Copy/paste the code from your `ShiftEncrypt` function that changes plaintext letters to plaintext numbers and labels the number `plaintext_number`. **Don't run the code yet.**","pos":2,"type":"cell"} -{"cell_type":"markdown","id":"08a9a1","input":"","pos":11,"type":"cell"} -{"cell_type":"markdown","id":"0c1309","input":"5. Test your Vigenère decryption function by using it to decrypt your ciphertext from Exercise 1.","pos":43,"type":"cell"} -{"cell_type":"markdown","id":"0de700","input":"4. Write a Vigenère **decryption** function by reversing the roles of ciphertext and plaintext in the chunk above where you defined the `VigenereEncrypt` function and changing only one other symbol in the code.","pos":41,"type":"cell"} -{"cell_type":"markdown","id":"0e4139","input":"","pos":28,"type":"cell"} -{"cell_type":"markdown","id":"1b7171","input":"Were the outputs of the `len` functions above what you expected? Why or why not?","pos":15,"type":"cell"} -{"cell_type":"markdown","id":"20fe0b","input":"Vigenère cycles between shifts in the following way. \n\n1. First off, the keyword is spelled out above the message, and repeated over and over again so that each letter in the message is associated with a letter from the keyword: \n
\nPlaintext: d i v e r t t r o o p s t o e a s t r i d g e\nKeyword:   W H I T E W H I T E W H I T E W H I T E W H I\n
\n2. To encrypt the first letter, we note that the plaintext 'd' lines up with the keyword 'W'. This means that we'll shift the 'd' forward by the amount encoded by 'W'.\n\nWhat does W correspond to in our letter-to-number chart, and what would be the result of shifting a 'd' forward by that number?","pos":8,"type":"cell"} -{"cell_type":"markdown","id":"2b6ad8","input":"# Vigenère Encryption Rubric (only grade bottom function and exercises)\n\nAll of the ciphers we've seen up to this point have been **monoalphabetic substitution ciphers**, meaning they use only one *cipher alphabet* (way of assigning a given plaintext letter to a ciphertext letter). Today, we'll work with a **polyalphabetic substitution cipher** for the first time, where (for example) a plaintext $e$ could be enciphered either as a ciphertext $O$ or a ciphertext $A$.\n\nAs usual, we'll start by telling Python that we're working with capital English letters. Run the chunk below to do this:","pos":0,"type":"cell"} -{"cell_type":"markdown","id":"30a77a","input":"So to figure out what key letter to add to a given plaintext letter, we just reduce the position of the plaintext letter modulo the key letter! For example, since 'I' is the sixth letter of 'FIREFIGHTER', we'd add the \n\n$$\n6\\mod{4} \\equiv 2\\text{nd}\n$$\n\nletter of the key to 'I'.\n\nBelow, I'll write the code to do this to the $i$th letter of `plaintext_numbers`, reduce mod 26, and label the result `ciphertext_number`. (Don't run it yet.)","pos":29,"type":"cell"} -{"cell_type":"markdown","id":"460bfb","input":"Continuing our steps for enciphering using Vigenere, the next step is to add the amount of the keyword shift to the plaintext, just as you did with the plaintext 'd' and 'i' in \"divert troops to east ridge\".\n\nYou've already written the code to convert both the plaintext to a number (`plaintext_number`) and the keyword to numbers (`key_number`). Below, write the code to add `key_number` to `plaintext_number` $\\mod{26}$ (but **don't run it**).","pos":19,"type":"cell"} -{"cell_type":"markdown","id":"48c40e","input":"The genius of Vigenère is that it uses a *keyword* to cycle between **multiple** shifts, so that a Vigenère cipher is actually multiple shift ciphers that we cycle through (like you cycled through two shifts in your reading question). Any idea how we could use a keyword to encode shifts? Write your answer below.","pos":4,"type":"cell"} -{"cell_type":"markdown","id":"52b94b","input":"OK, we're ready! Copy-paste lines (1.1), (1.2), and (1.3) of code in the chunk below. Below those, copy-paste the beginning of the `for` loop. Finally, tabbed over underneath the `for` command, copy-paste line (1.4) of code. Finally, still underneath the `for` loop, add code to convert `ciphertext_number` back to `ciphertext_letter` and append the result to the end of the string `ciphertext`. Then, outside the loop, have Python print the ciphertext.","pos":32,"type":"cell"} -{"cell_type":"markdown","id":"57e1dc","input":"2. What do you think would happen if you encrypted a Vigenère message using a key with only one letter (e.g. 'A')? Try encrypting the same message from Exercise 1 with the keyword 'B'. What happened? How secure is this cipher?","pos":36,"type":"cell"} -{"cell_type":"markdown","id":"62eadf","input":"Now, we want to start with an empty string of ciphertext (`''`) and add the corresponding keyword number to every plaintext number. Since we're repeating the step of adding the key letter to the plaintext letter for every letter in the plaintext, we'll need to use a `for` loop!\n\nRemember how we used code like `alph[3]` to find the third letter in the alphabet? That code really treated `alph` as a string and searched for the third character (i.e., letter) in the string, then output that letter. \n\nHow do you think we would output the zeroth (remember Python lists start at zero) letter in the string `keyword`? Write that code below (don't run it):","pos":21,"type":"cell"} -{"cell_type":"markdown","id":"67539a","input":"Finally, we'll assign the length of our `keyword` to the variable `key_length`. Write the code to output the length of the variable `keyword` and assign it to the name `key_length` using code below (don't run it):","pos":17,"type":"cell"} -{"cell_type":"markdown","id":"700c9e","input":"Similarly, since the plaintext 'i' aligns with the keyword 'H', we want to shift the 'i' forward by the amount encoded by the 'H'. What is that shift, and what is the result of shifting 'i' forward by this amount?","pos":10,"type":"cell"} -{"cell_type":"markdown","id":"73c74d","input":"","pos":9,"type":"cell"} -{"cell_type":"markdown","id":"88362a","input":"Now, we want to do this for every plaintext letter and the corresponding keyword letter using a `for` loop. Here's a shortcut: the code\n\n
\n(1.2)\nkey_numbers = [alph.find(i) for i in key]\n
\n\nturns every letter in the keyword into a number and stores the entire result in the string `key_numbers`. So, for example, if the keyword was \"HI\", `key_numbers` would be `[7, 8]` because $H=7$ and $I=8$ in our letter-to-number chart.\n\nBelow, write the code to convert the entire plaintext to numbers and call the result `plaintext_numbers` (mimic the `key_numbers` code above but change the names).","pos":25,"type":"cell"} -{"cell_type":"markdown","id":"97dc56","input":"3. Encrypt a reasonably-long message using a key of length 2 below. Then share the ciphertext with a partner at your table and see if they can break it!","pos":39,"type":"cell"} -{"cell_type":"markdown","id":"9c4d0f","input":"","pos":5,"type":"cell"} -{"cell_type":"markdown","id":"a33984","input":"## Exercises\n\n1. Test your shiny new function by encrypting two or three lines of lyrics by one of your favorite artists using the keyword 'MUSIC'.","pos":34,"type":"cell"} -{"cell_type":"markdown","id":"b545bf","input":"Since the key is repeated over and over again under the plaintext, it's important that we know the length of the keyword. \n\nIn Python, the code to output the length of a string (such as a keyword) is `len(string)`. For example, to find the length of the word \"ALLIGATOR\", we'd type\n\n
\nlen('ALLIGATOR')\n
\n\nBelow, write the code to find the length of the word \"SUPERCALIFRAGILISTICEXPIALIDOCIOUS\". In the second code chunk below, write the code to find the length of the variable `alph`, which we've assigned to the English alphabet.","pos":12,"type":"cell"} -{"cell_type":"markdown","id":"b7be84","input":"OK, we're ready to encipher a single plaintext letter! We want to perform the following steps:\n\n1. Define `alph` to be the capital English alphabet.\n2. Assign the length of the variable `keyword` to the variable `key_length`.\n3. Start with an empty string of ciphertext.\n4. Convert the first letter of the string `plaintext` to a number and call the result `plaintext_number`.\n5. Convert the first letter of the string `keyword` to a number and call the result `key_number`.\n6. Add the `key_number` to the `plaintext_number`, mod $26$, and call the result `ciphertext_number`.\n7. Convert the `ciphertext_number` back to a `ciphertext_letter`.\n8. Add `ciphertext_number` to the string `ciphertext`.\n\nAlmost all these steps are things we've done before in previous modules (e.g., converting letters to numbers and vice versa). Below, write the code to label the empty string `''` with the name `ciphertext`.","pos":23,"type":"cell"} -{"cell_type":"markdown","id":"c3ec68","input":"Just like we converted the plaintext to numbers, we need to convert the key to numbers as well. Below, write the code that would convert the variable `keyword` to numbers and label it `key_numbers`.","pos":6,"type":"cell"} -{"cell_type":"markdown","id":"ca3a7a","input":"","pos":16,"type":"cell"} -{"cell_type":"markdown","id":"d4acf2","input":"This is just a shift cipher with shift $B=+1$. This is not secure at all since it is vulnerable to frequency analysis and brute force.","pos":38,"type":"cell"} -{"cell_type":"markdown","id":"f1772e","input":"Now, we want to tell Python to repeat the keyword numbers over and over again under the plaintext numbers. For example, if the keyword is \"NICE\" and the plaintext is \"FIREFIGHTER\", we'd do the following:\n\n1. Convert both to numbers like you did above:\n
\nPlaintext:\n  \n  F  I  R  E  F  I  G  H  T  E  R\n  5  8  17 4  5  8  6  7  19 4  17\n\nKey:\n\n  N  I  C  E  N  I  C  E  N  I  C\n  13 8  2  4  13 8  2  4  13 8  2\n
\n\n2. Repeat the key over and over again under the plaintext, then add corresponding key letters to corresponding plaintext letters:\n\n
\nPlaintext:\n  \n  F  I  R  E  F  I  G  H  T  E  R\n  5  8  17 4  5  8  6  7  19 4  17\n\nKey:\n\n  N  I  C  E  N  I  C  E  N  I  C\n+ 13 8  2  4  13 8  2  4  13 8  2\n  ----------\n  18 16 19 8  18 16 8  11 ...\n  \n
\n\nHow do we tell Python to do this? Well, note that we're adding the first letter of the keyword to the first, fifth, and ninth letters of the plaintext (F, F, T). The length of the keyword here is 4. What time do 1, 5, and 9 all represent on a 4-hour clock?","pos":27,"type":"cell"} -{"id":0,"time":1637269208109,"type":"user"} -{"last_load":1637269208968,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/.VigenereEncrypt_Rubric.ipynb.sage-jupyter2 b/Python Modules/*Python Module Rubrics/.VigenereEncrypt_Rubric.ipynb.sage-jupyter2 deleted file mode 100755 index 60ed252..0000000 --- a/Python Modules/*Python Module Rubrics/.VigenereEncrypt_Rubric.ipynb.sage-jupyter2 +++ /dev/null @@ -1,3 +0,0 @@ -{"backend_state":"ready","kernel":"sage-8.8","kernel_state":"idle","kernel_usage":{"cpu":0,"memory":245665792},"trust":true,"type":"settings"} -{"end":1569521434768,"exec_count":1,"id":"daf627","input":"# Define a Vigenere encryption function\ndef VigenereEncrypt(plaintext, key):\n key_length = len(key)\n# Convert the key and plaintext from letters to numbers\n key_as_int = [ord(i) for i in key]\n plaintext_int = [ord(i) for i in plaintext]\n# Start with an empty string of ciphertext\n ciphertext = ''\n# Write the key over and over again underneath the plaintext, then add the two together and reduce modulo 26. Finally, convert the ciphertext numbers to letters and return the result.\n for i in range(len(plaintext_int)):\n value = (plaintext_int[i] + key_as_int[i % key_length]) % 26\n ciphertext += chr(value + 65)\n return ciphertext","kernel":"sage-8.8","pos":0,"start":1569521434732,"state":"done","type":"cell"} -{"last_load":1569521427136,"type":"file"} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/AffineEncrypt-rubric.ipynb b/Python Modules/*Python Module Rubrics/AffineEncrypt-rubric.ipynb deleted file mode 100755 index 8d1372c..0000000 --- a/Python Modules/*Python Module Rubrics/AffineEncrypt-rubric.ipynb +++ /dev/null @@ -1,270 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric\n", - "\n", - "- **50 Points**: student has a working `AffineEncrypt` function\n", - "- **10 Points**: student successfully reduces $45$ and $32\\mod{26}$\n", - "- **10 Points**: student explains that the cipher $C\\equiv 13P\\mod{26}$ sends every number to either $26 = A$ or $13 = N$.\n", - "- **30 Points**: student has a working `AffineEncryptX` function" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Python Module: Affine Cipher Encryption" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The affine cipher is more complicated than the shift cipher. This is good for encryption security, but makes the cipher even more cumbersome to implement by hand. In this Python module, you'll write a function that takes as inputs a plaintext message $P$, multiplicative key $m$, and additive key $k$, and outputs the ciphertext $C$ via the equation $C\\equiv mP+k\\mod{26}$. Then, you'll encrypt several messages with this function. Finally, you'll develop a new function that allows you to use a larger alphabet to affine-encipher messages, for example by adding characters such as !, ?, and *.\n", - "\n", - "Let's begin by outlining the code necessary to encrypt a message using the affine cipher. Luckily, it only takes a small modification of your `ShiftEncrypt` code to encrypt using an affine cipher. Instead of adding $k$, our shift, and then reducing $\\mod 26$, we're first multiplying by $m$, adding $k$, and reducing the result $\\mod 26$.\n", - "\n", - "The code to multiply 3 by 7 in Python is `3*7`. The code for the linear function $y=3x+7$ in Python is `y=3*x+7`.\n", - "\n", - "If the plaintext letter in our code was 'n', which is 13 on our letter-to-number chart, write the code to encrypt 'n' using the affine cipher $C\\equiv 3P+7\\mod{26}$ in the chunk below. Test that, when you run the code, you get the number $20$, corresponding to the ciphertext letter U." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "20" - ] - }, - "execution_count": 1, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "Mod(3*13 + 7, 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, the plaintext letter that we're encrypting is not always going to be M, and our keys are not always going to be $m=3$ and $k=7$. Below, write the code to multiply the variable $m$ times the variable $P$, then add $k$. Finally, wrap this code in the parentheses after the word Mod(). **Don't run the code chunk below.**" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "Mod(m*P + k, 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, under the line `def AffineEncrypt(plaintext, m, k)`, copy-paste the code under the line `def ShiftEncrypt(plaintext, key)` from the `ShiftEncrypt` module (toward the very end, where you're defining the `ShiftEncrypt` function for the first time). Finally, change your code so instead of just adding $k$, we're multiplying by $m$ first and then adding $k$. Then run the chunk below (nothing should happen yet)." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Copy-paste your ShiftEncrypt function below and then make the designated changes.\n", - "def AffineEncrypt(plaintext, m, k):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " ciphertext = ''\n", - " for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(m*plaintext_number + k, 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - " print(ciphertext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Now it's your turn!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Use your affine encryption function to encrypt the following messages with their corresponding keys:\n", - "\n", - "1. \"GOGRIFFINS\", $m = 5$, $k = 7$\n", - "2. \"CRYPTOGRAPHYISAWESOME\", $m = 17$, $k = 4$\n", - "3. \"STOPHAMMERTIME\", $m = 45$, $k = 32$.\n", - "4. \"NANANANANANANANANABATMAN\", $m = 13$, $k = 0$. " - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "LZLOVGGVUT\n", - "MHWZPICHEZTWKYEOUYIAU\n", - "KDMFJGAAERDCAE\n", - "NANANANANANANANANANANAAN\n" - ] - } - ], - "source": [ - "### Write your code for (1)-(4) here ###\n", - "AffineEncrypt('GOGRIFFINS',5,7)\n", - "AffineEncrypt('CRYPTOGRAPHYISAWESOME',17,4)\n", - "AffineEncrypt('STOPHAMMERTIME', 45, 32)\n", - "AffineEncrypt('NANANANANANANANANABATMAN', 13, 0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Look at the way Sage enciphered \"STOPHAMMERTIME\" with multiplicative key 45 and additive key 32. Using modular arithmetic, rewrite the equation $C\\equiv 45P+32\\mod{26}$ to an equivalent equation in which each number is reduced mod 26. Write that equation below; you may use = instead of $\\equiv$ for congruence. Test your equation by encrypting the letter \"S\" with it on a separate sheet of paper. Does the resulting ciphertext match that of the function?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Since 45 = 19 mod 26 and 32 = 6 mod 26, this cipher is equivalent to\n", - "\n", - "C = 19P + 6 mod 26" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "What happens to the word \"Batman\" in (4)? Why?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Every letter is converted to either N or A, where even letters are sent to 26 = A and odd letters are sent to 13 = N." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, define a function that uses a larger alphabet of your choice. For example, you could add the special characters ~!? to your alphabet. Be sure to adjust the modulus accordingly! Then, use this function to encrypt a message of your choice." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "!C!GWE?KTA\n" - ] - } - ], - "source": [ - "def AffineEncryptX(plaintext, m, k):\n", - " ### Write your code here ###\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ!?'\n", - " ciphertext = ''\n", - " for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(m*plaintext_number + k, 28)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - " print(ciphertext)\n", - "AffineEncryptX('YAYEUCLID!',15,2)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/BruteShift_rubric.ipynb b/Python Modules/*Python Module Rubrics/BruteShift_rubric.ipynb deleted file mode 100755 index 1f4e27e..0000000 --- a/Python Modules/*Python Module Rubrics/BruteShift_rubric.ipynb +++ /dev/null @@ -1,603 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric\n", - "\n", - "- (50 points) Student writes a working `BruteShift` function\n", - "- (50 points) Student writes an extended-alphabet `BruteShift` function and verifies it successfully brute-forces the ciphertext generated by their extended-alphabet `ShiftEncrypt` function" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Decrypting Shift Ciphers Using Brute Force\n", - "\n", - "## What is brute force?\n", - "\n", - "Let's say you intercept a message that you know was encrypted with a shift cipher, but you don't know the key. Is it possible to just try every possible key until you figure out what the message says?\n", - "\n", - "With shift ciphers and some other simple types of ciphers, the answer is yes! This is a good reason that the shift cipher is not currently used for military purposes. It was all well and good for Julius Caesar when no one was aware that shift ciphers existed, but now that they're commonly known, any shift-ciphered message could be broken by a (not particularly bright) computer in a few seconds.\n", - "\n", - "Breaking a cipher by **brute force** (or a **brute-force attack**) means trying to decrypt a message using all possible keys until you find a key that generates reasonable English plaintext. \n", - "\n", - "Let's start with a specific example. Say you encounter the ciphertext \"PBVHFUHW\", and you know it's been encrypted using a shift cipher (with unknown key). How would you execute a brute-force attack on this message with pen and paper? In the text box below, write out the steps you would take. How many possible keys would we have to try to decrypt a message that has been enciphered using an unknown shift cipher? Why?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## The `range` command\n", - "\n", - "It would be quite a pain to write out all those numbers each time we wanted to tell Python to try all shifts. Thankfully, Python has a built-in command that denotes all numbers in a given range.\n", - "\n", - "Say you want the numbers 0, 1, 2, 3, 4, 5, and 6. The \"Pythonic\" way of doing this is `range(0,7)`. Notice that the second number in the parentheses is never reached. So Python's \"syntax\" (the language it uses) for number ranges is ``range(first number, last number + 1)``. \n", - "\n", - "Below, write the Python command to print the numbers 1 through 23. Then run your command and see if it works. Remember that ``print(7)`` is the command to print the number 7. If your code doesn't work, talk to a group member or to your instructor." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "2\n", - "3\n", - "4\n", - "5\n", - "6\n", - "7\n", - "8\n", - "9\n", - "10\n", - "11\n", - "12\n", - "13\n", - "14\n", - "15\n", - "16\n", - "17\n", - "18\n", - "19\n", - "20\n", - "21\n", - "22\n", - "23\n" - ] - } - ], - "source": [ - "for number in range(1,24):\n", - " print(number)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Let's see how to decrypt the message 'PBVHFUHW' if all we know is that it was encrypted with a shift cipher (unknown shift). First, just like with encryption, we want to define a cipher alphabet: in this case, all capital English letters." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "What else do we need? Well, we have to tell the computer what plaintext we want to decrypt. Just like we did in the previous Sage module, we label our plaintext with the variable ``plaintext``. After we type the line below, every time we write ``plaintext``, Sage will replace it with ``'PBVHFUHW'``. That way, we don't have to remember and re-type the ciphertext every time we want to refer to it." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Input the ciphertext we want to decrypt\n", - "\n", - "ciphertext = 'PBVHFUHW'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, go back to the `ShiftEncrypt` Sage module. What was our next step in that case? Would we be able to use the same next step here? Why or why not? Write your answer below." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "*Our next step in the `ShiftEncrypt` module was to tell the program our key. We can't do that here because we don't know the key.*" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "It looks like we're going to have to try every possible shift between $0$ and $25$, including $0$ and $25$. Below, write the `range` command that describes the range of numbers $0,1,2,\\dots,25$. Then test your command by running it and verifying that it prints the correct set of numbers. If it doesn't work, talk to someone." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[0,\n", - " 1,\n", - " 2,\n", - " 3,\n", - " 4,\n", - " 5,\n", - " 6,\n", - " 7,\n", - " 8,\n", - " 9,\n", - " 10,\n", - " 11,\n", - " 12,\n", - " 13,\n", - " 14,\n", - " 15,\n", - " 16,\n", - " 17,\n", - " 18,\n", - " 19,\n", - " 20,\n", - " 21,\n", - " 22,\n", - " 23,\n", - " 24,\n", - " 25]" - ] - }, - "execution_count": 2, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "range(0,26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Testing all shifts using a `for` loop\n", - "\n", - "Great! You've found the code that describes the range of numbers $0,1,2,3,\\dots,25$. Now we want the computer to try every possible one of these numbers as a shift. In other words, `for` every one of these numbers, we want to try the ShiftDecrypt process we encoded in the last module.\n", - "\n", - "Here's a great thing about Python: it's \"stackable\". In other words, now that we've written the code to decrypt a message with known key, we don't need to rewrite it again. We can simply copy/paste that code into this module. Then, whenever we want to try a specific key, say $7$, on a specific message, say \"GJKRGE\", we can just write\n", - "\n", - "``ShiftDecrypt('GJKRGE',7)``.\n", - "\n", - "Below, copy/paste your function from code chunk (1.7) of the ShiftDecrypt module and run it. (It shouldn't do anything, but running it in this worksheet means the `ShiftDecrypt` command is now accessible to us for the rest of the module.)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def ShiftDecrypt(ciphertext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " plaintext = ''\n", - " for letter in ciphertext:\n", - " ciphertext_number = alph.find(letter)\n", - " plaintext_number = Mod(ciphertext_number - key, 26)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - " print(plaintext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Time for our `for` loop! For every possible shift between $0$ and $25$, we want to try `ShiftDecrypt`ing the ciphertext using that shift. \n", - "\n", - "Underneath the `for` loop below, tabbed over, write the code that would allow you to run the function `ShiftDecrypt` on the variable `ciphertext` with the key being the variable `shift`. (Basically, you can ignore all this stuff about \"variables\" when writing the code and just put the names of the variables in the function.)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PBVHFUHW\n", - "OAUGETGV\n", - "NZTFDSFU\n", - "MYSECRET\n", - "LXRDBQDS\n", - "KWQCAPCR\n", - "JVPBZOBQ\n", - "IUOAYNAP\n", - "HTNZXMZO\n", - "GSMYWLYN\n", - "FRLXVKXM\n", - "EQKWUJWL\n", - "DPJVTIVK\n", - "COIUSHUJ\n", - "BNHTRGTI\n", - "AMGSQFSH\n", - "ZLFRPERG\n", - "YKEQODQF\n", - "XJDPNCPE\n", - "WICOMBOD\n", - "VHBNLANC\n", - "UGAMKZMB\n", - "TFZLJYLA\n", - "SEYKIXKZ\n", - "RDXJHWJY\n", - "QCWIGVIX\n" - ] - } - ], - "source": [ - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "# Input the ciphertext we want to decrypt\n", - "\n", - "ciphertext = 'PBVHFUHW'\n", - "\n", - "for shift in range(0,26):\n", - " ShiftDecrypt(ciphertext, shift)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Test your code by running it. Can you figure out what the plaintext corresponding to the ciphertext 'PBVHFUHW'? If so, write that plaintext below and discuss how you found it. If not, explain why not." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "- The plaintext must be the only readable English text output by the `for` loop: \"MYSECRET\"." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, based on your investigations so far, discuss how secure you think the shift cipher is. Would you use the shift cipher to send a message to a friend? To store the password to your Facebook/Instagram/Snapchat account? What about to send military messages? Explain your answers." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## The `BruteShift` function\n", - "\n", - "Now, we'll write a function that allows us to brute force any intercepted shift-enciphered message. As before, when shift ciphers are used in the real world, the ciphertext is almost certain not to be 'PBVHFUHW'. Instead of this specific ciphertext, we want to allow ourselves the freedom to *define* whatever ciphertext we want. In other words, we want ``ciphertext`` to be the *input* to a function.\n", - "\n", - "We can almost exactly recycle our code from above, where we brute-force decrypted 'PBVHFUHW'. However, we'll need to replace any references to specific ciphertext with the variable `ciphertext`.\n", - "\n", - "In the code box below, remove all references to the ciphertext 'PBVHFUHW', leaving only references to the variable `ciphertext`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The chunk above should have again spit out the $26$ possible plaintexts corresponding to the plaintext 'PBVHFUHW'. This is because we've already told Python in the previous section that `ciphertext` is a placeholder for the text 'DOFCOMWUYMUL'. \n", - "\n", - "As before, to save us from having to write out all this code anytime we want to decrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to brute-force decrypt the message 'AJTQETA',\n", - "\n", - "``BruteShift('AJTQETA')``\n", - "\n", - "Just like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the y-value $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n", - "\n", - "Remember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def BruteShift(ciphertext):\n", - " for shift in range(0,26):\n", - " ShiftDecrypt(ciphertext, shift)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Exercises\n", - "\n", - "1. Use your shiny new function to decrypt the phrase \"DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB\" (spaces removed) given that it was encrypted with a shift cipher. Write the code you use to do this and run that code below." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB\n", - "CKKZYKZAOIQOPJKPUEAHZPKXNQPABKNYA\n", - "BJJYXJYZNHPNOIJOTDZGYOJWMPOZAJMXZ\n", - "AIIXWIXYMGOMNHINSCYFXNIVLONYZILWY\n", - "ZHHWVHWXLFNLMGHMRBXEWMHUKNMXYHKVX\n", - "YGGVUGVWKEMKLFGLQAWDVLGTJMLWXGJUW\n", - "XFFUTFUVJDLJKEFKPZVCUKFSILKVWFITV\n", - "WEETSETUICKIJDEJOYUBTJERHKJUVEHSU\n", - "VDDSRDSTHBJHICDINXTASIDQGJITUDGRT\n", - "UCCRQCRSGAIGHBCHMWSZRHCPFIHSTCFQS\n", - "TBBQPBQRFZHFGABGLVRYQGBOEHGRSBEPR\n", - "SAAPOAPQEYGEFZAFKUQXPFANDGFQRADOQ\n", - "RZZONZOPDXFDEYZEJTPWOEZMCFEPQZCNP\n", - "QYYNMYNOCWECDXYDISOVNDYLBEDOPYBMO\n", - "PXXMLXMNBVDBCWXCHRNUMCXKADCNOXALN\n", - "OWWLKWLMAUCABVWBGQMTLBWJZCBMNWZKM\n", - "NVVKJVKLZTBZAUVAFPLSKAVIYBALMVYJL\n", - "MUUJIUJKYSAYZTUZEOKRJZUHXAZKLUXIK\n", - "LTTIHTIJXRZXYSTYDNJQIYTGWZYJKTWHJ\n", - "KSSHGSHIWQYWXRSXCMIPHXSFVYXIJSVGI\n", - "JRRGFRGHVPXVWQRWBLHOGWREUXWHIRUFH\n", - "IQQFEQFGUOWUVPQVAKGNFVQDTWVGHQTEG\n", - "HPPEDPEFTNVTUOPUZJFMEUPCSVUFGPSDF\n", - "GOODCODESMUSTNOTYIELDTOBRUTEFORCE\n", - "FNNCBNCDRLTRSMNSXHDKCSNAQTSDENQBD\n", - "EMMBAMBCQKSQRLMRWGCJBRMZPSRCDMPAC\n" - ] - } - ], - "source": [ - "BruteShift('DLLAZLABPJRPQKLQVFBIAQLYORQBCLOZB')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "2. Below, define a function that uses brute force to decrypt a message that was encrypted using the larger alphabet from Exercise $2$ from the `ShiftDecrypt` module. Be sure to adjust the modulus accordingly!" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# this is just one possible example\n", - "\n", - "# first redefine the `ShiftDecryptX` function from Exercise 2 of the ShiftDecrypt module\n", - "\n", - "def ShiftDecryptX(ciphertext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n", - " plaintext = ''\n", - " for letter in ciphertext:\n", - " ciphertext_number = alph.find(letter)\n", - " plaintext_number = Mod(ciphertext_number - key, 29)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - " print(plaintext)\n", - " \n", - "# then define the BruteShiftX function to try every possible shift modulo the alphabet size from their ShiftDecryptX function (or whatever they've named it):\n", - "\n", - "def BruteShiftX(ciphertext):\n", - " for key in range(0,29):\n", - " ShiftDecryptX(ciphertext, key)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "3. Finally, test your new function by first using your beefed-up `ShiftEncrypt` function from Exercise 2 of that assignment to encrypt a message. Then, in the box below, input the encrypted message and run your beefed-up `BruteDecrypt` function from Exercise $2$ above to decrypt it. Did you get the plaintext you started with? Why or why not?" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KMLICW\n", - "JLKHBV\n", - "IKJGAU\n", - "HJIF!T\n", - "GIHE?S\n", - "FHGD~R\n", - "EGFCZQ\n", - "DFEBYP\n", - "CEDAXO\n", - "BDC!WN\n", - "ACB?VM\n", - "!BA~UL\n", - "?A!ZTK\n", - "~!?YSJ\n", - "Z?~XRI\n", - "Y~ZWQH\n", - "XZYVPG\n", - "WYXUOF\n", - "VXWTNE\n", - "UWVSMD\n", - "TVURLC\n", - "SUTQKB\n", - "RTSPJA\n", - "QSROI!\n", - "PRQNH?\n", - "OQPMG~\n", - "NPOLFZ\n", - "MONKEY\n", - "LNMJDX\n" - ] - } - ], - "source": [ - "# Write the code to decrypt your encrypted message here.\n", - "BruteShiftX('KMLICW')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Here, describe whether you got the plaintext you started with and why or why not." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/DUE_DATE.txt b/Python Modules/*Python Module Rubrics/DUE_DATE.txt deleted file mode 100755 index 8223402..0000000 --- a/Python Modules/*Python Module Rubrics/DUE_DATE.txt +++ /dev/null @@ -1,3 +0,0 @@ -This assignment is due - - 12/11/2019, 10:00:00 AM \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/Euclidean_Algorithm-Rubric.ipynb b/Python Modules/*Python Module Rubrics/Euclidean_Algorithm-Rubric.ipynb deleted file mode 100755 index 7b5496d..0000000 --- a/Python Modules/*Python Module Rubrics/Euclidean_Algorithm-Rubric.ipynb +++ /dev/null @@ -1,457 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric\n", - "\n", - "- **60 points**: student has a working Euclidean Algorithm function\n", - "- **40 points**: student successfully runs the function to compute each of:\n", - " - $\\gcd(213,543)$\n", - " - $\\gcd(32132,54254)$\n", - " - $\\gcd(12341324,543513543)$" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# The Euclidean Algorithm with Python" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The goal of this Python module is to give you a greater understanding of the Euclidean Algorithm by designing a function to compute the greatest common divisor $\\gcd(a,b)$ of two whole numbers $a$ and $b$.\n", - "\n", - "Recall the steps in the Euclidean Algorithm when computing $\\gcd(a,b)$, assuming $a < b$:\n", - "\n", - "1. Divide the larger of $a$ and $b$ by the smaller. Since we're assuming $a < b$, we'd divide $b$ by $a$.\n", - "2. Keep the remainder and $a$. Since the remainder of $b/a$ is smaller than $a$, let's rename $a$ to $b$, and call the remainder our new $a$.\n", - "For example, after dividing $b=13$ by $a=5$, we get a remainder of $3$. We'd then rename $a=3$, $b=5$.\n", - "3. Repeat this process until one of your numbers becomes $0$. Since at each stage we rename $a$ to be the smaller of the two numbers, we'd repeat until $a=0$.\n", - "4. At this point, the gcd is the other (nonzero) number, $b$.\n", - "\n", - "We need to figure out how to ask Python to take the remainder of $b/a$. What mathematical process do we already know how to do in Python that would give us the remainder? Write your answer below." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**The `Mod` or % functions reduce $b\\mod{a}$, which is the same thing as taking the remainder of $b/a$.**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In Python, the code for \"reduce a modulo b\" is `Mod(a,b)` or, equivalently, `a % b`. For example, to reduce $43 \\mod 26$, you'd write `Mod(43,26)` or `43 % 26`. (Here, when you see the \"percent\" symbol, think of division and finding a remainder.)\n", - "\n", - "Below, write and run the code to reduce each of the following:\n", - "1. $263 \\mod 123$\n", - "2. $548 \\mod 32$\n", - "3. $91042 \\mod 8321$" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "17" - ] - }, - "execution_count": 5, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "# 1.\n", - "263%123" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "4" - ] - }, - "execution_count": 3, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "# 2.\n", - "548%32" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "7832" - ] - }, - "execution_count": 4, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "# 3.\n", - "91042%8321" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, let's write code for each step in the Euclidean Algorithm. For now, let's assume that $a\\neq 0$ and that $a\\lt b$.\n", - "\n", - "In the first step of the Euclidean Algorithm, we replace $b$ with $b\\mod a$. In Python, \"replace $x$ with $y$\" is written `x = y`.\n", - "\n", - "Below, write the code to replace $b$ with $b \\mod a$." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "b = b % a" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Step 2 is to repeat Step 1 \"until one of our numbers is 0\". The way we do this in Python is with a *`while` loop*. A `while` loop says \"run the code below as long as some statement is true\". Contrast with a `for` loop, which runs e.g. for every number in a given range. In a `while` loop, the loop will stop once the specified condition is *no longer* met.\n", - "\n", - "Just like a `for` loop, when beginning a `while` loop, you enter a colon. Everything that should be repeated is tabbed over. Once the loop ends, anything you want Python to do afterwards is not tabbed over.\n", - "\n", - "Here's a simple example of a while loop:\n", - "\n", - "```\n", - "x = 1\n", - "while x < 4:\n", - " print x\n", - " x = x + 1\n", - "```\n", - "\n", - "This code says \"start with $x=1$. Then, as long as $x$ is less than $4$, print out $x$, then replace $x$ with $x+1$. Stop doing this as soon as $x\\geq 4$.\" What do you think this code will do? Write your guess below. Then run the code in the next box to see what it does. Did you guess right?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**The code should spit out [1, 2, 3] and then stop, since when $x=3$ the `while loop` would print $3$, replace $3$ with $4$, and at that point the condition $x<4$ would no longer be met.**" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "2\n", - "3\n" - ] - } - ], - "source": [ - "x = 1\n", - "while x < 4:\n", - " print x\n", - " x = x + 1" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In our case, we want to run code as long as $a \\neq 0$, since this means the code will stop when $a=0$. In Python, \"not equal to\" is written `!=`. (The exclamation mark is \"crossing out\" the equals sign.) So, for example, to say \"$x$ is not equal to $5$\", you'd write `x != 5`.\n", - "\n", - "Below, write the first line of a while loop that will run as long as $a \\neq 0$. Remember to put a colon after the first line, and don't run your code yet! Underneath your first line, tabbed over, write the code to replace $b$ with $b \\mod a$. This code corresponds to steps 1 and 2 of our algorithm." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.1\n", - "while a != 0:\n", - " b = b % a" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Think through how the Euclidean Algorithm would work for $a=2,b=3$. First it would reduce $b\\mod{a}$, getting a new $b$-value of $1$. At this point, $a=2$ and $b=1$. What happens at this stage if we try to reduce $b\\mod{a}$? Explain your answer." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**We'd get $1\\mod{2}=1$. Nothing would change.**" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "For the reason you mentioned above, if we continued replacing $b$ with $b\\mod{a}$ at each step, never changing the roles of $a$ or $b$, the code would never stop running. This is because reducing a smaller number modulo a bigger number *doesn't change the smaller number*. On a clock with $2$ hours, 1:00 is just 1:00!\n", - "\n", - "The way we'll fix this is by telling Python to interchange the roles of $a$ and $b$ after each reduction step. The code to do this is `a,b=b,a`. This tells Python to take the value to the left of the first comma ($a$) and replace it with the value to the left of the second comma ($b$). Simultaneously, this code tells Python to replace the value to the *right* of the first comma ($b$) with the value to the *right* of the second comma ($a$). Overall, thus, the code interchanges the roles of $a$ and $b$.\n", - "\n", - "Below, copy-paste your code from (1.1), but then add the code to interchange the values of $a$ and $b$ tabbed over **below the `while` loop**." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.2\n", - "while a != 0:\n", - " b = b % a\n", - " a,b = b,a" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We're almost done! After completing steps 1 and 2, the last step is to have the code spit out the nonzero number. Since our loop runs *until* $a = 0$, at the end of our loop, $a = 0$. So $b$ is the nonzero number we want.\n", - "\n", - "Remember that the Pythonic expression for \"spit `something` out\" is `print something` (here you'd replace the variable `something` with whatever variable you want to return). Below, copy-paste your code from (1.2), but this time, add code below your while loop to spit out the number $b$, which will be our gcd. **Don't run your code yet**; we'll do that once we define a function below." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.3\n", - "while a != 0:\n", - " b = b % a\n", - " a,b = b,a\n", - "print b" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, last step! Let's make a *function* out of your code so we don't need to write all of the code out every time we want to compute a gcd. Do you remember how functions work? The first line looks like `def name_of_function(input1, input2):`. Everything under the first line that's part of the function gets tabbed over.\n", - "\n", - "In the code block below, define a function called `EA` which takes as inputs two whole numbers $a$ and $b$ where $a\\lt b$ and spits out $\\gcd(a,b)$. (Hint: after writing the line which `def`s your function, just copy/paste your code from earlier below that line. Make sure you tab everything under the `def` line over once, and you'll need another tab underneath the `while` line!)\n", - "\n", - "Actually, Sage (the app we're using to code in Python) already has a built-in `gcd` function. **So it's important we don't call our function `gcd`.**" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.4 Defining a function\n", - "def EA(a,b):\n", - " while a != 0:\n", - " b = b % a\n", - " a,b = b,a\n", - " print b" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "And for your last question on this assignment, test your brand-new gcd function on a few pairs of numbers! In the code chunk below, tell your function to compute the following:\n", - "1. $\\gcd(213,543)$\n", - "2. $\\gcd(32132,54254)$\n", - "3. $\\gcd(12341324,543513543)$\n", - "\n", - "Remember that, in order to use a function you've written, you have to write the name of the function, open parentheses, inputs to the function separated by commas, and close parentheses. For example, to run a function called `zookeeper` on the inputs `monkey, lion, tiger`, you'd write\n", - "\n", - "```\n", - "zookeeper(monkey, lion, tiger)\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "#1.\n", - "EA(213, 543)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n" - ] - } - ], - "source": [ - "#2.\n", - "EA(32132, 54254)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "73\n" - ] - } - ], - "source": [ - "#3. \n", - "EA(12341234, 543513543)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.4", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 10, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.4", - "resource_dir": "/ext/jupyter/kernels/sage-9.4" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.15" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/Frequency_Analysis_Instructor.ipynb b/Python Modules/*Python Module Rubrics/Frequency_Analysis_Instructor.ipynb deleted file mode 100755 index 7aaa7de..0000000 --- a/Python Modules/*Python Module Rubrics/Frequency_Analysis_Instructor.ipynb +++ /dev/null @@ -1,320 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Python Module: Frequency Analysis\n", - "\n", - "Frequency analysis is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n", - "\n", - "For example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be an encrypted body of text that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n", - "\n", - "To begin, let's look at the code for a frequency count of the text \"TEST\".\n", - "\n", - "We'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n", - "\n", - "It's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 to our `count_list` 26 times.\n", - "\n", - "Do you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses after `range` in the line `for i in range():`**" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false, - "scrolled": true - }, - "outputs": [ - ], - "source": [ - "# 1.1\n", - "alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - "message = \"TEST\"\n", - "\n", - "count_list = []\n", - "\n", - "## Edit the line of code below ##\n", - "for i in range(0,26):\n", - " count_list.append(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about e.g. spaces).\n", - "We do this by going through our message letter by letter and adding each letter to our list.\n", - "This is done using the command `.append`. \n", - "\n", - "Whenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n", - "\n", - "If our list were called `cool_list`, the code to do this would be as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# start with a blank list\n", - "cool_list = []\n", - "for i in message:\n", - " cool_list.append(i)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "## Write your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n", - "\n", - "The code to add 1 to the 19th entry of `count_list` is:\n", - "\n", - "```\n", - "count_list[19] += 1\n", - "```\n", - "\n", - "Here, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1.\n", - "\n", - "**In place of the line \"`## write your code here ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.**" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "ename": "NameError", - "evalue": "name 'letter_list' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;31m# 1.2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# counts occurences of each letter\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0;32mfor\u001b[0m \u001b[0mx\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mletter_list\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 4\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mInteger\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m26\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mx\u001b[0m \u001b[0;34m==\u001b[0m \u001b[0malphabet\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mNameError\u001b[0m: name 'letter_list' is not defined" - ] - } - ], - "source": [ - "# 1.2\n", - "# counts occurences of each letter\n", - "for x in letter_list:\n", - " for i in range(0,26):\n", - " if x == alphabet[i]:\n", - " ## write your code below ##\n", - " count_list[i] += 1" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The code above spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n", - "\n", - "```\n", - "[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n", - "```\n", - "\n", - "where the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the 18th spot reflects the count of $T = 18$.\n", - "\n", - "Do you see any problems? \n", - "\n", - "It's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n", - "\n", - "The way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n", - "\n", - "Similarly, we'll get the entries \n", - "\n", - "```\n", - "['B',0], ['C',0], ['D',0], ['E',1],\n", - "```\n", - "\n", - "etc.\n", - "\n", - "The Python command to merge two lists together is `zip(list1, list2)`. **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.3\n", - "# pair each letter of the alphabet with its frequency in a new list\n", - "\n", - "## Write your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes.\n", - "\n", - "The way Python sorts lists is with the command \n", - "\n", - "```\n", - "{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by])\n", - "```\n", - "\n", - "Here, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n", - "\n", - "In this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is the first column in the list, since `alphabet` is considered the zeroth column).\n", - "\n", - "Below, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.4\n", - "\n", - "# sort by decreasing order of relative frequency and return the frequencies together with the corresponding ciphertext letters\n", - "\n", - "## write your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.4) above in order and run it in order to perform a frequency count on the message `'TEST'`.**" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.5\n", - "## Copy-paste your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n", - "\n", - "As usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n", - "\n", - "**Copy-paste your code from (1.5) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def freq_analysis(message):\n", - " ## copy-paste and edit your code here to define the function ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n", - "\n", - "For example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "#Tests\n", - "\n", - "## write your code here ##" - ] - } - ], - "metadata": { - "kernelspec": { - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.15" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/Frequency_Analysis_Rubric2.ipynb b/Python Modules/*Python Module Rubrics/Frequency_Analysis_Rubric2.ipynb deleted file mode 100755 index 6446107..0000000 --- a/Python Modules/*Python Module Rubrics/Frequency_Analysis_Rubric2.ipynb +++ /dev/null @@ -1,437 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Python Module: Frequency Analysis\n", - "\n", - "**Frequency analysis** is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n", - "\n", - "For example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be a ciphertext message that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n", - "\n", - "To begin, let's look at the code for a frequency count of the text \"TEST\".\n", - "\n", - "We'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n", - "\n", - "It's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 onto the end of our `count_list` 26 times.\n", - "\n", - "Why can't we just use `+=` for this? We can, but Python is a bit finicky about how it treats lists of numbers. If we wrote `count_list += 0`, we'd get an error (try it below if you'd like). This is because `+=` can only add *lists* to other lists, while `.append` can add numbers.\n", - "\n", - "Since our `count_list` is made up of numbers, we'll have to use the command `count_list.append(0)`. To append any number `n` to a list (call it my_list), the same idea works: we'd write `my_list.append(n)`.\n", - "\n", - "Do you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses in the line \"`for i in range():`\"**" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false, - "scrolled": true - }, - "outputs": [ - ], - "source": [ - "# 1.1\n", - "alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - "message = \"TEST\"\n", - "\n", - "count_list = []\n", - "\n", - "## Edit the line of code below ##\n", - "for i in range(0,26):\n", - " count_list.append(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about spaces).\n", - "We do this by going through our message letter by letter and adding each letter to our list.\n", - "This can be done using the command `.append`, just as we used for numbers above.\n", - "\n", - "Whenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n", - "\n", - "If our list were called `cool_list`, the code to do this would be as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# start with a blank list\n", - "cool_list = []\n", - "\n", - "# add every letter in the message to the list\n", - "for letter in message:\n", - " cool_list.append(letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.2\n", - "## Write your code here ##\n", - "letter_list = []\n", - "# add every letter in the message to the list\n", - "for letter in message:\n", - " letter_list.append(letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n", - "\n", - "The code to add 1 to the 19th entry of `count_list` is:\n", - "\n", - "```\n", - "count_list[19] += 1\n", - "```\n", - "\n", - "Here, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1. (When operating on single numbers and not lists, `+=` works great!)\n", - "\n", - "**In place of the line \"`## write your code below ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.** Hint: copy-paste the code above, but change 19 to the variable `i`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.3\n", - "# counts occurences of each letter\n", - "for letter in letter_list:\n", - " for i in range(0,26):\n", - " if letter == alphabet[i]:\n", - " count_list[i] += 1\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The code above spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n", - "\n", - "```\n", - "[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n", - "```\n", - "\n", - "where the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the $19$th spot reflects the count of $T = 19$.\n", - "\n", - "Do you see any problems? \n", - "\n", - "It's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n", - "\n", - "The way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n", - "\n", - "Similarly, we'll get the entries \n", - "\n", - "```\n", - "['B',0], ['C',0], ['D',0], ['E',1],\n", - "```\n", - "\n", - "etc.\n", - "\n", - "The Python command to merge two lists together is `zip(list1, list2)` (think of literally taking the two lists with a zipper between them and zipping up the zipper to join them side by side). **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.4\n", - "# pair each letter of the alphabet with its frequency in a new list\n", - "letter_freq = zip(alphabet, count_list)\n", - "## Write your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes. Then we could immediately tell what the most common ciphertext letter was and guess it came from plaintext e.\n", - "\n", - "The way Python sorts lists is with the command \n", - "\n", - "```\n", - "{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by], reverse = True)\n", - "```\n", - "\n", - "Here, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n", - "\n", - "In this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is numbered as the first column in the list, since `alphabet` is considered the zeroth column). \n", - "\n", - "The `reverse = True` line means that letters with higher frequencies will come first in the list instead of last, which is the default option.\n", - "\n", - "Below, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.5\n", - "\n", - "# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n", - "\n", - "sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\n", - "print sorted_letter_freq\n", - "\n", - "## write your code here ##" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.5) above in order and run it in order to perform a frequency count on the message `'TEST'`.**" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n" - ] - } - ], - "source": [ - "# 1.1\n", - "alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - "message = \"TEST\"\n", - "\n", - "count_list = []\n", - "\n", - "## Edit the line of code below ##\n", - "for i in range(0,26):\n", - " count_list.append(0)\n", - "\n", - "# 1.2\n", - "## Write your code here ##\n", - "letter_list = []\n", - "# add every letter in the message to the list\n", - "for letter in message:\n", - " letter_list.append(letter)\n", - "\n", - "# 1.3\n", - "# counts occurences of each letter\n", - "for letter in letter_list:\n", - " for i in range(0,26):\n", - " if letter == alphabet[i]:\n", - " count_list[i] += 1\n", - "\n", - "# 1.4\n", - "# pair each letter of the alphabet with its frequency in a new list\n", - "letter_freq = zip(alphabet, count_list)\n", - "## Write your code here ##\n", - "\n", - "# 1.5\n", - "\n", - "# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n", - "\n", - "sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\n", - "print sorted_letter_freq" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n", - "\n", - "As usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n", - "\n", - "**Copy-paste your code from (1.6) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def freq_analysis(message):\n", - " # 1.1\n", - " alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - " count_list = []\n", - "\n", - " ## Edit the line of code below ##\n", - " for i in range(0,26):\n", - " count_list.append(0)\n", - "\n", - " # 1.2\n", - " ## Write your code here ##\n", - " letter_list = []\n", - " # add every letter in the message to the list\n", - " for letter in message:\n", - " letter_list.append(letter)\n", - "\n", - "# 1.3\n", - "# counts occurences of each letter\n", - " for letter in letter_list:\n", - " for i in range(0,26):\n", - " if letter == alphabet[i]:\n", - " count_list[i] += 1\n", - "\n", - "# 1.4\n", - "# pair each letter of the alphabet with its frequency in a new list\n", - " letter_freq = zip(alphabet, count_list)\n", - "## Write your code here ##\n", - "\n", - "# 1.5\n", - "\n", - "# sort by decreasing order of relative frequency and print the frequencies together with the corresponding ciphertext letters\n", - "\n", - "sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\n", - "print sorted_letter_freq" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n", - "\n", - "For example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "#Tests\n", - "\n", - "#1.\n", - "## write your code here ##" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "#2.\n", - "## write your code here ##" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "#3.\n", - "## write your code here ##" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/Frequency_Analysis_rubric.ipynb b/Python Modules/*Python Module Rubrics/Frequency_Analysis_rubric.ipynb deleted file mode 100755 index 33805eb..0000000 --- a/Python Modules/*Python Module Rubrics/Frequency_Analysis_rubric.ipynb +++ /dev/null @@ -1,455 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric\n", - "\n", - "**Give full credit if students have a function that outputs the letter frequencies either from greatest to least or least to greatest. A recent update to Python changed the code so that the code I outlined should only order from least to greatest.**\n", - "\n", - "- If students don't have a working frequency analysis function, give 20 points for each of the following labeled chunks that has the correct code:\n", - " - (1.1)\n", - " - (1.2)\n", - " - (1.3)\n", - " - (1.4)\n", - " - (1.5)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Python Module: Frequency Analysis\n", - "\n", - "Frequency analysis is the process of counting the number of occurrences of ciphertext letters in order to make a guess about what plaintext letters they came from. Frequency analysis only works for *monoalphabetic substitution ciphers*, in which letters are always enciphered the same way (for example, every 'e' in the plaintext is enciphered as a 'T'). Frequency analysis breaks down (though it can be modified to work) in the case of *polyalphabetic substitution ciphers*, in which different occurences of a plaintext letter could be enciphered differently. (For example, one 'e' may be enciphered as a 'T' and another as an 'R'.)\n", - "\n", - "For example: For the text \"TEST\" the frequency of 'E' is 1, 'S' is 1 and 'T' is 2. The input to the function will be an encrypted body of text that only contains the capital letters A-Z. As output, we will print a list of the frequency for each of the letters A-Z.\n", - "\n", - "To begin, let's look at the code for a frequency count of the text \"TEST\".\n", - "\n", - "We'll start with an empty `count_list`, then initialize the count at zero for each of the $26$ capital English letters. The following code chunk will (once you fix it) initialize the count of each letter as $0$. In other words, the code chunk will add $26$ zeroes to our list of letter counts. \n", - "\n", - "It's much easier to use a `for` loop here rather than adding 26 zeroes to our list by hand. In other words, we want to tell our computer to \"append\" 0 to our `count_list` 26 times.\n", - "\n", - "Do you remember how to specify the range of numbers between 0 and 25, including 0 and 25? **Edit the chunk of code below to add the correct numerical range in between the parentheses after `range` in the line `for i in range():`**" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false, - "scrolled": true - }, - "outputs": [ - ], - "source": [ - "# 1.1\n", - "alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - "message = \"TEST\"\n", - "\n", - "count_list = []\n", - "\n", - "## Edit the line of code below ##\n", - "for i in range(0,26):\n", - " count_list.append(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "For technical reasons, we need to convert our message string to a list of letters (so we can count letters without worrying about e.g. spaces).\n", - "We do this by going through our message letter by letter and adding each letter to our list.\n", - "This is done using the command `.append`. \n", - "\n", - "Whenever you have a list in Python, you can add numbers or strings to the end of the list by writing `listname.append(object)`, replacing `listname` with the name of your list and `object` with the string or number you'd like to add to your list.\n", - "\n", - "If our list were called `cool_list`, the code to do this would be as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# start with a blank list\n", - "cool_list = []\n", - "for i in message:\n", - " cool_list.append(i)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, write the code to begin with a blank list called `letter_list` (the underscore is essential because Python can't read spaces in variable names) and append all the letters in our message to `letter_list`. (Hint: copy the code chunk above and just change the name of the list.)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "## Write your code here ##\n", - "letter_list = []\n", - "for letter in message:\n", - " letter_list.append(letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we need to go through `count_list` and add each occurrence of each letter. For example, in the word 'TEST', we want to start at the first T in the message and add $1$ to the entry of `count_list` corresponding to the letter T. Since $T = 19$, we want to add 1 to the 19th entry of `count_list` every time we see a T.\n", - "\n", - "The code to add 1 to the 19th entry of `count_list` is:\n", - "\n", - "```\n", - "count_list[19] += 1\n", - "```\n", - "\n", - "Here, \"+=\" denotes that we're replacing the 19th entry of `count_list` with the 19th entry of `count_list` plus 1.\n", - "\n", - "**In place of the line \"`## write your code here ##`\", copy and paste the code to replace the $i$th entry of `count_list` with the $i$th entry plus 1.**" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.2\n", - "# counts occurences of each letter\n", - "for x in letter_list:\n", - " for i in range(0,26):\n", - " if x == alphabet[i]:\n", - " ## write your code below ##\n", - " count_list[i] += 1" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The code above (once we add a `print(count_list)` command to the end; don't worry about that yet) spits out a list of 26 numbers, where each number is equal to the number of occurrences of the corresponding letter. For example, if we run the above code on the message `'TEST'`, we'd get the list\n", - "\n", - "```\n", - "[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,0,0,0,0,0,0]\n", - "```\n", - "\n", - "where the 1s in the 4th and 17th spots in the list (remember, Python starts counting at 0) reflect the counts of the letters $E = 4$ and $S = 17$, and the 2 in the 18th spot reflects the count of $T = 18$.\n", - "\n", - "Do you see any problems? \n", - "\n", - "It's annoying to have to count how far out in the list we are in order to determine what letter's frequency we're looking at. It would be ideal if each spot in the list was \"labeled\" with the corresponding letter.\n", - "\n", - "The way we'll do this is by *merging* our `alphabet` list with `count_list`. This takes the first entries in each list, in this case `'A'` and `0`, and merges them together into the entry `['A',0]`.\n", - "\n", - "Similarly, we'll get the entries \n", - "\n", - "```\n", - "['B',0], ['C',0], ['D',0], ['E',1],\n", - "```\n", - "\n", - "etc.\n", - "\n", - "The Python command to merge two lists together is `zip(list1, list2)`. **Below, write the command to merge the lists `alphabet` and `count_list` together, then name your \"zipped\" list `letter_freq`**." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# 1.3\n", - "# pair each letter of the alphabet with its frequency in a new list\n", - "\n", - "## Write your code here ##\n", - "letter_freq = zip(alphabet,count_list)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Lastly, it'd be useful to sort our list from most frequent to least frequent in order to use it to break codes.\n", - "\n", - "The way Python sorts lists is with the command \n", - "\n", - "```\n", - "{name of new sorted list} = sorted({list to sort}, key = lambda {name of column to sort by}: {name of column to sort by}[number of column to sort by])\n", - "```\n", - "\n", - "Here, I use curly brackets `{}` to denote where you fill in the blanks. There should be no curly brackets in your code.\n", - "\n", - "In this case, we want to sort the list `letter_freq` according to the values in the column `count_list` (which is the first column in the list, since `alphabet` is considered the zeroth column).\n", - "\n", - "Below, write the code to perform this sort, name the new sorted list `sorted_letter_freq`, then print the list `sorted_letter_freq`." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n" - ] - } - ], - "source": [ - "# 1.4\n", - "\n", - "# sort by decreasing order of relative frequency and return the frequencies together with the corresponding ciphertext letters\n", - "\n", - "sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\n", - "print sorted_letter_freq" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, let's bring it all together. **Below, copy-paste all your code from (1.1)-(1.4) above in order and run it in order to perform a frequency count on the message `'TEST'`.**" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('T', 2), ('E', 1), ('S', 1), ('A', 0), ('B', 0), ('C', 0), ('D', 0), ('F', 0), ('G', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n" - ] - } - ], - "source": [ - "# 1.5\n", - "## Copy-paste your code here ##\n", - "alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - "message = \"TEST\"\n", - "\n", - "letter_list = []\n", - "for i in message:\n", - " letter_list.append(i)\n", - "\n", - "count_list = []\n", - "\n", - "## Edit the line of code below ##\n", - "for i in range(0,26):\n", - " count_list.append(0)\n", - "\n", - "# counts occurences of each letter\n", - "for x in letter_list:\n", - " for i in range(0,26):\n", - " if x == alphabet[i]:\n", - " ## write your code below ##\n", - " count_list[i] += 1\n", - "\n", - "letter_freq = zip(alphabet,count_list)\n", - "sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse = True)\n", - "print(sorted_letter_freq)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, we don't just want code to perform frequency analysis on one message; we want to be able to input any message and have our code perform frequency analysis on that message.\n", - "\n", - "As usual, we'll define a *function* that takes as input a `message` and outputs the list of letter frequencies in the message, sorted from greatest to least.\n", - "\n", - "**Copy-paste your code from (1.5) above, changing your code as necessary, in order to define such a function `freq_analysis` below. Remember to add a line that `print`s `sorted_letter_freq`, the list of sorted letter frequencies, at the end of your function.**" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def freq_analysis(message):\n", - " ## copy-paste and edit your code here to define the function ##\n", - " alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M',\n", - " 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z']\n", - " letter_list = []\n", - " for i in message:\n", - " letter_list.append(i)\n", - " count_list = []\n", - " for i in range(0,26):\n", - " count_list.append(0)\n", - "\n", - " # counts occurences of each letter\n", - " for x in letter_list:\n", - " for i in range(0,26):\n", - " if x == alphabet[i]:\n", - " count_list[i] += 1\n", - " letter_freq = zip(alphabet,count_list)\n", - " sorted_letter_freq = sorted(letter_freq, key = lambda count_list: count_list[1], reverse=True)\n", - " print(sorted_letter_freq)" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "**Once you think you have a working function, test it below by performing frequency analysis on three messages of your choice.** \n", - "\n", - "For example, the code to do a frequency analysis on the message \"CABBAGE\" would be `freq_analysis(\"CABBAGE\")`." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('E', 859), ('T', 639), ('O', 513), ('N', 483), ('A', 477), ('S', 477), ('I', 449), ('R', 424), ('H', 348), ('D', 252), ('L', 228), ('U', 209), ('C', 184), ('F', 180), ('M', 144), ('P', 138), ('G', 130), ('W', 97), ('B', 95), ('Y', 81), ('V', 74), ('J', 16), ('K', 14), ('X', 9), ('Q', 6), ('Z', 4)]\n" - ] - } - ], - "source": [ - "#Tests\n", - "\n", - "## write your code here ##\n", - "freq_analysis(\"WHEN IN THE COURSE OF HUMAN EVENTS IT BECOMES NECESSARY FOR ONE PEOPLE TO DISSOLVE THE POLITICAL BANDS WHICH HAVE CONNECTED THEM WITH ANOTHER AND TO ASSUME AMONG THE POWERS OF THE EARTH, THE SEPARATE AND EQUAL STATION TO WHICH THE LAWS OF NATURE AND OF NATURE'S GOD ENTITLE THEM, A DECENT RESPECT TO THE OPINIONS OF MANKIND REQUIRES THAT THEY SHOULD DECLARE THE CAUSES WHICH IMPEL THEM TO THE SEPARATION. WE HOLD THESE TRUTHS TO BE SELF-EVIDENT, THAT ALL MEN ARE CREATED EQUAL, THAT THEY ARE ENDOWED BY THEIR CREATOR WITH CERTAIN UNALIENABLE RIGHTS, THAT AMONG THESE ARE LIFE, LIBERTY AND THE PURSUIT OF HAPPINESS. — THAT TO SECURE THESE RIGHTS, GOVERNMENTS ARE INSTITUTED AMONG MEN, DERIVING THEIR JUST POWERS FROM THE CONSENT OF THE GOVERNED, — THAT WHENEVER ANY FORM OF GOVERNMENT BECOMES DESTRUCTIVE OF THESE ENDS, IT IS THE RIGHT OF THE PEOPLE TO ALTER OR TO ABOLISH IT, AND TO INSTITUTE NEW GOVERNMENT, LAYING ITS FOUNDATION ON SUCH PRINCIPLES AND ORGANIZING ITS POWERS IN SUCH FORM, AS TO THEM SHALL SEEM MOST LIKELY TO EFFECT THEIR SAFETY AND HAPPINESS. PRUDENCE, INDEED, WILL DICTATE THAT GOVERNMENTS LONG ESTABLISHED SHOULD NOT BE CHANGED FOR LIGHT AND TRANSIENT CAUSES; AND ACCORDINGLY ALL EXPERIENCE HATH SHEWN THAT MANKIND ARE MORE DISPOSED TO SUFFER, WHILE EVILS ARE SUFFERABLE THAN TO RIGHT THEMSELVES BY ABOLISHING THE FORMS TO WHICH THEY ARE ACCUSTOMED. BUT WHEN A LONG TRAIN OF ABUSES AND USURPATIONS, PURSUING INVARIABLY THE SAME OBJECT EVINCES A DESIGN TO REDUCE THEM UNDER ABSOLUTE DESPOTISM, IT IS THEIR RIGHT, IT IS THEIR DUTY, TO THROW OFF SUCH GOVERNMENT, AND TO PROVIDE NEW GUARDS FOR THEIR FUTURE SECURITY. — SUCH HAS BEEN THE PATIENT SUFFERANCE OF THESE COLONIES; AND SUCH IS NOW THE NECESSITY WHICH CONSTRAINS THEM TO ALTER THEIR FORMER SYSTEMS OF GOVERNMENT. THE HISTORY OF THE PRESENT KING OF GREAT BRITAIN IS A HISTORY OF REPEATED INJURIES AND USURPATIONS, ALL HAVING IN DIRECT OBJECT THE ESTABLISHMENT OF AN ABSOLUTE TYRANNY OVER THESE STATES. TO PROVE THIS, LET FACTS BE SUBMITTED TO A CANDID WORLD. HE HAS REFUSED HIS ASSENT TO LAWS, THE MOST WHOLESOME AND NECESSARY FOR THE PUBLIC GOOD. HE HAS FORBIDDEN HIS GOVERNORS TO PASS LAWS OF IMMEDIATE AND PRESSING IMPORTANCE, UNLESS SUSPENDED IN THEIR OPERATION TILL HIS ASSENT SHOULD BE OBTAINED; AND WHEN SO SUSPENDED, HE HAS UTTERLY NEGLECTED TO ATTEND TO THEM. HE HAS REFUSED TO PASS OTHER LAWS FOR THE ACCOMMODATION OF LARGE DISTRICTS OF PEOPLE, UNLESS THOSE PEOPLE WOULD RELINQUISH THE RIGHT OF REPRESENTATION IN THE LEGISLATURE, A RIGHT INESTIMABLE TO THEM AND FORMIDABLE TO TYRANTS ONLY. HE HAS CALLED TOGETHER LEGISLATIVE BODIES AT PLACES UNUSUAL, UNCOMFORTABLE, AND DISTANT FROM THE DEPOSITORY OF THEIR PUBLIC RECORDS, FOR THE SOLE PURPOSE OF FATIGUING THEM INTO COMPLIANCE WITH HIS MEASURES. HE HAS DISSOLVED REPRESENTATIVE HOUSES REPEATEDLY, FOR OPPOSING WITH MANLY FIRMNESS HIS INVASIONS ON THE RIGHTS OF THE PEOPLE.HE HAS REFUSED FOR A LONG TIME, AFTER SUCH DISSOLUTIONS, TO CAUSE OTHERS TO BE ELECTED, WHEREBY THE LEGISLATIVE POWERS, INCAPABLE OF ANNIHILATION, HAVE RETURNED TO THE PEOPLE AT LARGE FOR THEIR EXERCISE; THE STATE REMAINING IN THE MEAN TIME EXPOSED TO ALL THE DANGERS OF INVASION FROM WITHOUT, AND CONVULSIONS WITHIN.HE HAS ENDEAVOURED TO PREVENT THE POPULATION OF THESE STATES; FOR THAT PURPOSE OBSTRUCTING THE LAWS FOR NATURALIZATION OF FOREIGNERS; REFUSING TO PASS OTHERS TO ENCOURAGE THEIR MIGRATIONS HITHER, AND RAISING THE CONDITIONS OF NEW APPROPRIATIONS OF LANDS. HE HAS OBSTRUCTED THE ADMINISTRATION OF JUSTICE BY REFUSING HIS ASSENT TO LAWS FOR ESTABLISHING JUDICIARY POWERS. HE HAS MADE JUDGES DEPENDENT ON HIS WILL ALONE FOR THE TENURE OF THEIR OFFICES, AND THE AMOUNT AND PAYMENT OF THEIR SALARIES. HE HAS ERECTED A MULTITUDE OF NEW OFFICES, AND SENT HITHER SWARMS OF OFFICERS TO HARASS OUR PEOPLE AND EAT OUT THEIR SUBSTANCE. HE HAS KEPT AMONG US, IN TIMES OF PEACE, STANDING ARMIES WITHOUT THE CONSENT OF OUR LEGISLATURES. HE HAS AFFECTED TO RENDER THE MILITARY INDEPENDENT OF AND SUPERIOR TO THE CIVIL POWER. HE HAS COMBINED WITH OTHERS TO SUBJECT US TO A JURISDICTION FOREIGN TO OUR CONSTITUTION, AND UNACKNOWLEDGED BY OUR LAWS; GIVING HIS ASSENT TO THEIR ACTS OF PRETENDED LEGISLATION: FOR QUARTERING LARGE BODIES OF ARMED TROOPS AMONG US: FOR PROTECTING THEM, BY A MOCK TRIAL FROM PUNISHMENT FOR ANY MURDERS WHICH THEY SHOULD COMMIT ON THE INHABITANTS OF THESE STATES: FOR CUTTING OFF OUR TRADE WITH ALL PARTS OF THE WORLD:FOR IMPOSING TAXES ON US WITHOUT OUR CONSENT:FOR DEPRIVING US IN MANY CASES, OF THE BENEFIT OF TRIAL BY JURY:FOR TRANSPORTING US BEYOND SEAS TO BE TRIED FOR PRETENDED OFFENCES:FOR ABOLISHING THE FREE SYSTEM OF ENGLISH LAWS IN A NEIGHBOURING PROVINCE, ESTABLISHING THEREIN AN ARBITRARY GOVERNMENT, AND ENLARGING ITS BOUNDARIES SO AS TO RENDER IT AT ONCE AN EXAMPLE AND FIT INSTRUMENT FOR INTRODUCING THE SAME ABSOLUTE RULE INTO THESE COLONIESFOR TAKING AWAY OUR CHARTERS, ABOLISHING OUR MOST VALUABLE LAWS AND ALTERING FUNDAMENTALLY THE FORMS OF OUR GOVERNMENTS:FOR SUSPENDING OUR OWN LEGISLATURES, AND DECLARING THEMSELVES INVESTED WITH POWER TO LEGISLATE FOR US IN ALL CASES WHATSOEVER.HE HAS ABDICATED GOVERNMENT HERE, BY DECLARING US OUT OF HIS PROTECTION AND WAGING WAR AGAINST US.HE HAS PLUNDERED OUR SEAS, RAVAGED OUR COASTS, BURNT OUR TOWNS, AND DESTROYED THE LIVES OF OUR PEOPLE.HE IS AT THIS TIME TRANSPORTING LARGE ARMIES OF FOREIGN MERCENARIES TO COMPLEAT THE WORKS OF DEATH, DESOLATION, AND TYRANNY, ALREADY BEGUN WITH CIRCUMSTANCES OF CRUELTY & PERFIDY SCARCELY PARALLELED IN THE MOST BARBAROUS AGES, AND TOTALLY UNWORTHY THE HEAD OF A CIVILIZED NATION.HE HAS CONSTRAINED OUR FELLOW CITIZENS TAKEN CAPTIVE ON THE HIGH SEAS TO BEAR ARMS AGAINST THEIR COUNTRY, TO BECOME THE EXECUTIONERS OF THEIR FRIENDS AND BRETHREN, OR TO FALL THEMSELVES BY THEIR HANDS.E HAS EXCITED DOMESTIC INSURRECTIONS AMONGST US, AND HAS ENDEAVOURED TO BRING ON THE INHABITANTS OF OUR FRONTIERS, THE MERCILESS INDIAN SAVAGES WHOSE KNOWN RULE OF WARFARE, IS AN UNDISTINGUISHED DESTRUCTION OF ALL AGES, SEXES AND CONDITIONS.IN EVERY STAGE OF THESE OPPRESSIONS WE HAVE PETITIONED FOR REDRESS IN THE MOST HUMBLE TERMS: OUR REPEATED PETITIONS HAVE BEEN ANSWERED ONLY BY REPEATED INJURY. A PRINCE, WHOSE CHARACTER IS THUS MARKED BY EVERY ACT WHICH MAY DEFINE A TYRANT, IS UNFIT TO BE THE RULER OF A FREE PEOPLE.NOR HAVE WE BEEN WANTING IN ATTENTIONS TO OUR BRITISH BRETHREN. WE HAVE WARNED THEM FROM TIME TO TIME OF ATTEMPTS BY THEIR LEGISLATURE TO EXTEND AN UNWARRANTABLE JURISDICTION OVER US. WE HAVE REMINDED THEM OF THE CIRCUMSTANCES OF OUR EMIGRATION AND SETTLEMENT HERE. WE HAVE APPEALED TO THEIR NATIVE JUSTICE AND MAGNANIMITY, AND WE HAVE CONJURED THEM BY THE TIES OF OUR COMMON KINDRED TO DISAVOW THESE USURPATIONS, WHICH WOULD INEVITABLY INTERRUPT OUR CONNECTIONS AND CORRESPONDENCE. THEY TOO HAVE BEEN DEAF TO THE VOICE OF JUSTICE AND OF CONSANGUINITY. WE MUST, THEREFORE, ACQUIESCE IN THE NECESSITY, WHICH DENOUNCES OUR SEPARATION, AND HOLD THEM, AS WE HOLD THE REST OF MANKIND, ENEMIES IN WAR, IN PEACE FRIENDS.WE, THEREFORE, THE REPRESENTATIVES OF THE UNITED STATES OF AMERICA, IN GENERAL CONGRESS, ASSEMBLED, APPEALING TO THE SUPREME JUDGE OF THE WORLD FOR THE RECTITUDE OF OUR INTENTIONS, DO, IN THE NAME, AND BY AUTHORITY OF THE GOOD PEOPLE OF THESE COLONIES, SOLEMNLY PUBLISH AND DECLARE, THAT THESE UNITED COLONIES ARE, AND OF RIGHT OUGHT TO BE FREE AND INDEPENDENT STATES, THAT THEY ARE ABSOLVED FROM ALL ALLEGIANCE TO THE BRITISH CROWN, AND THAT ALL POLITICAL CONNECTION BETWEEN THEM AND THE STATE OF GREAT BRITAIN, IS AND OUGHT TO BE TOTALLY DISSOLVED; AND THAT AS FREE AND INDEPENDENT STATES, THEY HAVE FULL POWER TO LEVY WAR, CONCLUDE PEACE, CONTRACT ALLIANCES, ESTABLISH COMMERCE, AND TO DO ALL OTHER ACTS AND THINGS WHICH INDEPENDENT STATES MAY OF RIGHT DO. — AND FOR THE SUPPORT OF THIS DECLARATION, WITH A FIRM RELIANCE ON THE PROTECTION OF DIVINE PROVIDENCE, WE MUTUALLY PLEDGE TO EACH OTHER OUR LIVES, OUR FORTUNES, AND OUR SACRED HONOR.\")" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('A', 2), ('B', 2), ('C', 1), ('E', 1), ('G', 1), ('D', 0), ('F', 0), ('H', 0), ('I', 0), ('J', 0), ('K', 0), ('L', 0), ('M', 0), ('N', 0), ('O', 0), ('P', 0), ('Q', 0), ('R', 0), ('S', 0), ('T', 0), ('U', 0), ('V', 0), ('W', 0), ('X', 0), ('Y', 0), ('Z', 0)]\n" - ] - } - ], - "source": [ - "freq_analysis('CABBAGE')" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('E', 15), ('N', 13), ('A', 11), ('O', 11), ('T', 11), ('R', 10), ('H', 6), ('I', 5), ('S', 5), ('U', 5), ('C', 4), ('D', 4), ('F', 4), ('L', 4), ('G', 2), ('P', 2), ('B', 1), ('M', 1), ('Q', 1), ('V', 1), ('W', 1), ('Y', 1), ('J', 0), ('K', 0), ('X', 0), ('Z', 0)]\n" - ] - } - ], - "source": [ - "freq_analysis('FOUR SCORE AND SEVEN YEARS AGO OUR FATHERS BROUGHT FORTH ON THIS CONTINENT A NEW NATION FOUNDED ON THE PRINCIPLE THAT ALL MEN ARE CREATED EQUAL')" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/ShiftDecrypt_rubric.ipynb b/Python Modules/*Python Module Rubrics/ShiftDecrypt_rubric.ipynb deleted file mode 100755 index ce1bc30..0000000 --- a/Python Modules/*Python Module Rubrics/ShiftDecrypt_rubric.ipynb +++ /dev/null @@ -1,733 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric\n", - "\n", - "- 50 points: student's `ShiftDecrypt` function correctly decrypts `SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ` as `LIFELIBERTYANDTHEPURSUITOFHAPPINESS`.\n", - "- 10 points: in Exercise 1, students correctly decrypt with a shift of $27$ and justify why decrypting with a $-27$ shift is equivalent to decrypting with a $-1$ shift modulo $26$.\n", - "- 40 points: student verifies that running their extended-alphabet `ShiftEncrypt` function on some plaintext of their choice, then running their extended-alphabet `ShiftDecrypt` function on the resulting ciphertext, gives back the initial plaintext." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Decrypting Shift Ciphers with Known Key\n", - "\n", - "## Decrypting a single letter\n", - "\n", - "If we know the key, decrypting a letter that was encrypted using a shift cipher just requires undoing the encryption steps. In the last module, we performed the following four steps to encrypt a letter using a shift cipher:\n", - "\n", - "1. Convert the plaintext letter to a plaintext number.\n", - "2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is $3$. In other words, we're taking the plaintext number plus the key, mod $26$, to get the ciphertext number. \n", - "3. Convert the ciphertext number to a ciphertext letter. \n", - "4. Append that letter to our output ciphertext.\n", - "\n", - "In order to *undo* this process, we'll have to undo each step *backwards*. If you were given a cipheretxt letter (say 'D') and a key (say $20$), what would be your first step if you were trying to decrypt the letter? In words (not Sage code), describe this step in the box below. **Hint**: for time and accuracy reasons, you probably don't want to recite the alphabet backwards by $20$ letters." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "*Convert the ciphertext letter to a ciphertext number.*" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Undoing step $3$\n", - "\n", - "Effectively, we're *undoing* step 3 first. Here is the code we used to encrypt a letter (given by the variable `plaintext`) in our previous Sage module. Note that, just like with encryption, we first want to define a cipher alphabet: in this case, all capital English letters." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "# Start with an empty string of ciphertext\n", - "\n", - "ciphertext = ''\n", - "\n", - "# Carry out the encryption steps\n", - "\n", - "# 1. Convert the plaintext letter to a plaintext number.\n", - "\n", - "plaintext_number = alph.find(letter)\n", - "\n", - "# 2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is 3. In other words, we're taking the plaintext number plus the key, mod 26, to get the ciphertext number. \n", - "\n", - "ciphertext_number = Mod(plaintext_number + key, 26)\n", - "\n", - "# 3. Convert the ciphertext number to a ciphertext letter.\n", - "\n", - "ciphertext_letter = alph[ciphertext_number]\n", - "\n", - "# 4. Append that letter to our output ciphertext.\n", - "\n", - "ciphertext += ciphertext_letter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, however, we're starting with ciphertext, given unsurprisingly by the variable `ciphertext`, and we want to *end up with* plaintext. Just like we did above, we'll start with an empty string of plaintext using the command\n", - "\n", - "``plaintext = ''``\n", - "\n", - "(don't worry too much about how this works).\n", - "\n", - "Above, step $3$ converted our ciphertext numbers to ciphertext letters using the `alph` command. Step $1$ converted letters to numbers using the `alph.find` command. Which command, `alph` or `alph.find`, do we want to use to convert our ciphertext letters to numbers? Write your answer below." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 3, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "alph.find('D')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, say we're given the ciphertext letter 'D'. Below, I'll start with an empty string of plaintext, then assign the variable `ciphertext_letter` to the letter 'D' and the variable `key` to the value $20$ (don't worry too much about how this works). Below my code, write the code to convert the variable `ciphertext_letter` to a number using the command you wrote above, either `alph` or `alph.find`. Then run your code to see if it works and talk to someone if it doesn't." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 4, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "# Begin with an empty string of plaintext\n", - "\n", - "plaintext = ''\n", - "\n", - "# Input our ciphertext letter and key\n", - "\n", - "ciphertext_letter = 'D'\n", - "key = 20\n", - "\n", - "# Your code goes below\n", - "\n", - "alph.find(ciphertext_letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Great! If your code worked, you should end up with the number $3$. Below, copy-paste your line of code from above after the equals sign in order to assign this $3$ to the variable `ciphertext_number`." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.1) This step converts a ciphertext letter to a ciphertext number and stores the number\n", - "\n", - "ciphertext_number = alph.find(ciphertext_letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, what do we want to do to this number in order to decrypt it? In words (not Sage code), describe this step in the box below. " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "*Shift it back by 20, mod 26*" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Undoing step $2$\n", - "\n", - "We now want to undo step $2$ of the process above. Step $2$ took our plaintext number and added the key, mod $26$, to get our ciphertext number.\n", - "\n", - "Now, we're starting with a ciphertext number and want to go back to a plaintext number. Below, I've recopied the code for step $2$ of the encryption process. Alter the code in order to make it *decrypt* instead of *encrypt*. **Hint**: take the modular arithmetic equation we used to decrypt shift ciphers in class, $P\\equiv C-k\\mod{26}$, and replace $P$ with `plaintext_number`, $C$ with `ciphertext_number`, and $k$ with `key`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.2) Once you edit the code below, it should decrypt instead of encrypt.\n", - "\n", - "# 2. To get a ciphertext number, shift the plaintext number up by the key, looping around so that, for example, Z is replaced with C when the key is 3. In other words, we're taking the plaintext number plus the key, mod 26, to get the ciphertext number. \n", - "plaintext_number = Mod(ciphertext_number - key, 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Undoing step $1$\n", - "\n", - "Great! We've undone steps $3$ and $2$; now to undo step $1$. When we were encrypting messages, step $1$ was to convert a plaintext letter to a plaintext number. However, when decrypting and after undoing steps $3$ and $2$, we end up with a plaintext *number*. How do we convert it to a plaintext letter? Below, write the code to convert the variable `plaintext_number` from a number to a letter. **Hint**: you're using either `alph` or `alph.find`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "alph(plaintext_number)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, just as before, we want to assign our new plaintext letter to the variable `plaintext_letter`. In order to do so, copy-paste your code from the box above after the equals sign below." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.3) The code below will convert a plaintext number to a plaintext letter.\n", - "\n", - "plaintext_letter = alph(plaintext_number)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Secret extra step: appending our letter to the output plaintext\n", - "\n", - "We're not quite done yet! Just like we appended our ciphertext letters to the output ciphertext in step 4 of the encryption process, we have to append our output *plain*text letters to the output *plain*text in step 4 of the *de*cryption process.\n", - "\n", - "The code below was used in the last module to append the variable `ciphertext_letter` to the variable `ciphertext`. Below, edit the code so that it appends the variable `plaintext_letter` to the variable `plaintext` instead." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.4) Edit this code so that it appends plaintext_letter to plaintext\n", - "\n", - "plaintext += plaintext_letter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Putting it all together\n", - "\n", - "Awesome! The code we've written so far takes the ciphertext letter 'D', assigns it to the variable `ciphertext_letter`, and does the following:\n", - "\n", - "1. Converts the ciphertext letter to a ciphertext number and stores this number in the variable `ciphertext_number`.\n", - "2. Subtracts the key from the ciphertext number and stores the result in the variable `plaintext_number`.\n", - "3. Converts the plaintext number to a plaintext letter and stores this letter in the variable `plaintext_letter`.\n", - "4. Appends the `plaintext_letter` to the output `plaintext`.\n", - "\n", - "In the code chunk below, copy the lines of code you wrote marked (1.1), (1.2), (1.3), and (1.4) all in order. This code contains the whole decryption process for a single ciphertext letter!" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.5) \n", - "ciphertext_number = alph.find(ciphertext_letter)\n", - "plaintext_number = Mod(ciphertext_number - key, 26)\n", - "plaintext_letter = alph(plaintext_number)\n", - "plaintext += plaintext_letter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Decrypting whole words\n", - "\n", - "Great! You've managed to shift one ciphertext letter to a plaintext letter. However, in order to decrypt messages, we're going to need to shift *multiple* ciphertext letters at once. To do this, we need the magic of ``for`` loops.\n", - "\n", - "You've already seen ``for`` loops in Codecademy and in the previous module. Basically, the idea is that we want to repeat a task, like shifting letters, over and over again. How many times do we want to repeat the task? Well, once for every letter in our ciphertext. The code to start this ``for`` loop is\n", - "\n", - "``for ciphertext_letter in ciphertext:``\n", - "\n", - "If you type the above line of code into a code chunk and hit enter, the next line will be tabbed over. Python uses whitespace as a way of managing what's inside a `for` loop and what's not. **Every bit of code you write that's tabbed over under a `for` loop will be run for every single letter of your ciphertext.** \n", - "\n", - "So what should we write tabbed over inside this `for` loop? I'm glad you asked. Once you've reached this point, try to help others around you until we're all at this point, and we'll talk as a class about what goes inside our `for` loop." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Let's do it!\n", - "\n", - "Are you back? Great! Let's try to write a `for` loop that decrypts the entire message 'DOFCOMWUYMUL', which was encrypted with the key $k=20$. \n", - "\n", - "Our goal is to replace the letter 'D' in our code above with a *variable*. Like in algebra, variables can take on many values. So far, we've already seen the variables ``alph``, ``plaintext``, ``key``, and ``ciphertext``. They are placeholders for letters or numbers that can be assigned values, just like the equation $x=3$ assigns the variable $x$ the value $3$.\n", - "\n", - "Below, I've started you off with the beginning of a `for` loop and the code we used to shift 'D' back by $20$. Edit that code by deleting all references to 'D' and replacing them with the variable ``letter``. Then the `for` loop will cycle through all the letters in the message 'DOFCOMWUYMUL' and shift *all* of them back by $20$. Then click Run on your edited chunk and see what happens. Once you click Run and observe the results, read the text below the chunk." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.6)\n", - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "# Start with an empty string of plaintext\n", - "\n", - "plaintext = ''\n", - "\n", - "# Input our ciphertext and key\n", - "\n", - "ciphertext = 'DOFCOMWUYMUL'\n", - "key = 20\n", - "\n", - "# Edit the code below to remove all references to 'D'\n", - "\n", - "for ciphertext_letter in ciphertext:\n", - " ciphertext_number = alph.find(ciphertext_letter)\n", - " plaintext_number = Mod(ciphertext_number - 20, 26)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Time to print!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "If you edited and ran the code above correctly, *nothing should have happened*. Why not? Well, we didn't actually tell Sage to *show* us the ciphertext.\n", - "\n", - "This might sound silly. Computer programs and programming languages are very smart in some ways and very dumb in others. To a human, it'd be obvious that, if we asked them to decrypt some ciphertext, they should actually tell us what the decrypted message says. To Python, not so much. We have to explicitly ask using the `print` command.\n", - "\n", - "The `print` command doesn't actually send anything to a printer. It just prints words, numbers, or letters on the screen.\n", - "\n", - "In our case, we want to print the plaintext, which we've conveniently assigned to the variable `plaintext`. In the code box below, copy-paste your code from chunk (1.5) above. Then, outside the tabbed section, write the command to print the variable `plaintext`. Then run the chunk and see what happens. You should see the ciphertext resulting from decrypting the word 'DOFCOMWUYMUL' with the key $20$." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.5)\n", - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "# Start with an empty string of plaintext\n", - "\n", - "plaintext = ''\n", - "\n", - "# Input our ciphertext and key\n", - "\n", - "ciphertext = 'DOFCOMWUYMUL'\n", - "key = 20\n", - "\n", - "# Edit the code below to remove all references to 'D'\n", - "\n", - "for ciphertext_letter in ciphertext:\n", - " ciphertext_number = alph.find(ciphertext_letter)\n", - " plaintext_number = Mod(ciphertext_number - 20, 26)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - "print(plaintext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Creating a Function\n", - "\n", - "Now, when shift ciphers are used in the real world, the ciphertext is almost certain not to be 'DOFCOMWUYMUL', and the key may not be $20$. Instead of this specific ciphertext and key, we want to allow ourselves the freedom to *define* whatever ciphertext and key we want. In other words, we want ``ciphertext`` and ``key`` to be *inputs* to a function.\n", - "\n", - "We can almost exactly recycle our code from above, where we decrypted 'DOFCOMWUYMUL' with a shift of $20$. However, we'll need to replace any references to specific ciphertext with the variable `ciphertext` and any references to specific numerical keys with the variable `key`.\n", - "\n", - "In the code box below, remove all references to the ciphertext 'DOFCOMWUYMUL', leaving only references to the variable `ciphertext`, and all references to the number $20$, leaving only references to the variable `key`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "JULIUSCAESAR\n" - ] - } - ], - "source": [ - "# (1.6)\n", - "# Define our cipher alphabet as all capital English letters\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - "\n", - "plaintext = ''\n", - "\n", - "# Edit the code below to remove all references to specific ciphertext or keys\n", - "\n", - "for letter in ciphertext:\n", - " ciphertext_number = alph.find(letter)\n", - " plaintext_number = Mod(ciphertext_number - key, 26)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - "\n", - "print(plaintext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The chunk above should have again spit out the plaintext corresponding to the ciphertext 'DOFCOMWUYMUL'. This is because we've already told Python in the previous section that `ciphertext` is a placeholder for the text 'DOFCOMWUYMUL' and `key` is a placeholder for the number $20$. What if we want to decrypt a different message using a different key? Do we have to write all this code out again, changing the values of the variables `ciphertext` and `key`? Thankfully, no!\n", - "\n", - "To save us from having to write out all this code anytime we want to decrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to decrypt the message 'AJTQETA' using the key $7$, all we'll have to write is\n", - "\n", - "``ShiftDecrypt('AJTQETA',7)``\n", - "\n", - "Just like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n", - "\n", - "The function we're dealing with doesn't just have one input, though, it has two: the ciphertext and the key. One of those inputs (the ciphertext) is a word and the other is a number.\n", - "\n", - "Remember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once, and everything in your `for` loop has to be tabbed over once more, so the stuff inside your `for` loop is *double*-tabbed! I\"ll start you off by defining the alphabet and the empty string called `plaintext` like we did above." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# (1.7)\n", - "def ShiftDecrypt(ciphertext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " plaintext = ''\n", - " for letter in ciphertext:\n", - " ciphertext_number = alph.find(letter)\n", - " plaintext_number = Mod(ciphertext_number - key, 26)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - " print(plaintext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, mimic my code in the 'AJTQETA' example above and use your function to decrypt the phrase 'SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ' with a shift of $7$. Yes, it was a lot of work to write the function, but now that we have the function, decryption is so much easier than it would be by hand! (**Hint**: you probably want to copy/paste the ciphertext.)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "LIFELIBERTYANDTHEPURSUITOFHAPPINESS\n" - ] - } - ], - "source": [ - "ShiftDecrypt(\"SPMLSPILYAFHUKAOLWBYZBPAVMOHWWPULZZ\",7)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Exercises\n", - "\n", - "Now that you have a function, try answering the following:\n", - "\n", - "1. What do you think happens if you try to *decrypt* use a key that's larger than your alphabet? Try decrypting the message 'QPUBUPFT' with a key of 27 and see! Is the result what you expected? Can you do some modular arithmetic to show why this is the case?" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "POTATOES\n" - ] - } - ], - "source": [ - "ShiftDecrypt(\"QPUBUPFT\",27)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Decrypting with a key of $27$ is the same as decrypting with a key of $1$. This is because $27\\equiv 1\\mod{26}$." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "2. Copy and paste the function above (changing its name) and try to change the code so that it decrypts using *the same* larger alphabet you used in the ShiftEncrypt module. Be sure to adjust the modulus accordingly!" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def ShiftDecryptX(ciphertext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n", - " plaintext = ''\n", - " for letter in ciphertext:\n", - " ciphertext_number = alph.find(letter)\n", - " plaintext_number = Mod(ciphertext_number - key, 29)\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - " print(plaintext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "3. Finally, test your new function by first using your beefed-up `ShiftEncrypt` function from Exercise 2 of that assignment to encrypt a message. Then, in the box below, input the encrypted message and run your beefed-up `ShiftDecrypt` function from Exercise 2 above to decrypt it. Did you get the plaintext you started with? Why or why not?" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "MONKEY\n" - ] - } - ], - "source": [ - "# Write the code to decrypt your encrypted message here.\n", - "\n", - "# Answer may vary. Example:\n", - "ShiftDecryptX('KMLICW', 27)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Here, describe whether you got the plaintext you started with and why or why not." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/ShiftEncrypt_rubric.ipynb b/Python Modules/*Python Module Rubrics/ShiftEncrypt_rubric.ipynb deleted file mode 100755 index aefa978..0000000 --- a/Python Modules/*Python Module Rubrics/ShiftEncrypt_rubric.ipynb +++ /dev/null @@ -1,843 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Rubric:\n", - "\n", - "- 50 points: `ShiftEncrypt` function encrypts `stargazer` as `JKRIXRQVI`\n", - "- 35 points: Student writes a working function in Exercise 2 that correctly encrypts their chosen plaintext in Exercise 3.\n", - "- 15 points: Student justifies why a shift of 27 is equivalent to a shift of 1 in a 26-letter alphabet in Exercise 1." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Shift Ciphers in Sage\n", - "\n", - "## Welcome!\n", - "\n", - "Welcome to your first Sage module for the course! Sage is a bunch of math-centric enhancements to the Python programming language. \n", - "\n", - "Does that mean you're expected to learn how to program in this course? Not at all! While you're welcome to play around and try to extend your code if you have prior programming experience (come talk to me about your plans if this is the case), most of what you'll be doing involves \"thoughtful copy-pasting\" of existing code.\n", - "\n", - "What is \"thoughtful copy/paste\"? When coding is new to people, it's almost impossible to type a line of code that will run without error. Why not find some code that you know will execute and modify it slightly? It's in that modification that one needs to be thoughtful. What do you need to change and why? The goal for this course is that you'll come out with a little more knowledge of how to tweak a single bit of code to suit your needs.\n", - "\n", - "Does this sound like cheating? It isn't a cop-out. It's helping everyone get to the point where Sage makes sense and will give results. In fact, you have some programming background and are interested in doing more with R, there are countless online resources you can visit to augment your learning. (The rest of the free Codecademy Python course is a good start.)\n", - "\n", - "## What's the point?\n", - "\n", - "So why are we using programming in a cryptography course? Frankly, because no one does cryptography anymore with pen and paper. While this may have been possible in Julius Caesar's time, nowadays cryptography is conducted almost exclusively on computers, by computer programs. In fact, by the end of this course, we'll be doing cryptography this is *literally impossible* to do by hand. This type of cryptography (RSA encryption) keeps credit card info safe online and is one of the most commonly used computer programs today.\n", - "\n", - "Even for older encryption systems like shift ciphers, it's still an enormous time-saver to use a computer to encrypt our messages. My goal in this course is to give you more time to focus on concepts than on the arithmetic and simple computations you need to encrypt shift ciphers. Once you understand the basics of how a cipher works, shifting repetitive tasks to a computer helps you focus on the broader concepts underlying each type of encryption.\n", - "\n", - "## Setting Up\n", - "\n", - "To this end, our goal is to play around with a small program that will encrypt text using a shift cipher. \n", - "\n", - "We want to be able to input any plaintext we want and the desired shift. The program should then spit out the ciphertext.\n", - "\n", - "First, we'll do an example, encoding the message \"MYSECRET\" using a shift of 3, like the classical Caesar cipher. You'll then use this example to define a function." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Don't change any of the lines beginning with # signs! These are \"comments\" (here used to give instructions) and don't affect what your code is doing.\n", - "# Don't mess with the code below; it just defines our cipher alphabet as all capital English letters. That means our ciphertext and plaintext will both be capital letters. This is a bit different from how we do things in class, but Python works differently.\n", - "\n", - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Our first step is to write the plaintext message we want to encrypt and label it with the variable ``plaintext``. After we type the line below, every time we write ``plaintext``, Python will replace it with ``'MYSECRET'``." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "plaintext = 'MYSECRET'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Next, we define the key. In this case, the key is the number of letters to the right we want to shift. (Note that negative keys correspond to left shifts.) As an example, let's use the classical Caesar cipher, which has a right shift of 3 letters. From now on, whenever we type the word ``key``, Python will replace it with the number 3." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "key = 3" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, now here's the tricky part. How do we actually shift every single letter of the plaintext ``'MYSECRET'`` over by 3? \n", - "\n", - "We'll do it one letter at a time using a \"for loop\" (remember these from your Intro to Python on Codecademy?).\n", - "\n", - "For weird reasons that aren't too important, we'll start with an empty ciphertext message and use a for loop to add ciphertext letters to it, one by one.\n", - "\n", - "Define the variable ``ciphertext`` to be an empty string of letters. This empty string is written as ``''``, two apostrophes with nothing (our empty word) between them." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "ciphertext = ''" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to go through every letter of the plaintext 'MYSECRET' and, one by one, replace these letters with ciphertext letters.\n", - "\n", - "In other words, for every letter in the plaintext, we want to do the following in order:\n", - "\n", - "1. Convert the plaintext letter to a plaintext number. Sage already has the ability to do this built-in.\n", - "2. To get a ciphertext number, shift the plaintext number up by 3, looping around so that, for example, Z is replaced with C. In other words, we're taking the plaintext number plus $3$, mod $26$, to get the ciphertext number. \n", - "3. Convert the ciphertext number to a ciphertext letter. \n", - "4. Append that letter to our output ciphertext.\n", - "\n", - "## Shifting a Single Letter\n", - "\n", - "This process can be tricky to understand, so let's go through it with a single letter first. Say we want to encrypt the letter M from 'MYSECRET'. What do we need to do?\n", - "\n", - "1. Convert the plaintext letter to a plaintext number. \n", - "\n", - "Sage does this using the function ``alph.find``. Recall that when Python deals with letters, you have to put apostrophes or quotation marks (it doesn't matter which) around them so that Python realizes they're letters. (Technically, Python counts anything within apostrophes or quotes as a \"string\", which is exactly how we want it to treat letters and words.) So to find which number corresponds to the letter M, we'd write:" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 6, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "alph.find('M')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Click on the code chunk above. Now, click on the button \"Run\" in the toolbar just below the \"File, Edit, View\" menu. What happens? Is this what you'd expect? Write your answer in the empty text box below this line." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We would expect this because the letter M corresponds to the number 12." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Let's store this plaintext number $12$ for later. In order to store answers, we'll have to give them names. Let's name this $12$, which is the plaintext number corresponding to the letter 'M'. We'll call it ``plaintext_number`` (no spaces are allowed in Python names).\n", - "\n", - "Recall that naming things in Python is done with the `=` sign. For example, to label the number $4$ with the word `banana`, we'd just write `banana = 4`.\n", - "\n", - "Later, we're going to generalize our code, so instead of just writing `plaintext_number = 12`, we'll remember that the $12$ came from the command `alph.find('M')`. Thus, we'll label `alph_find('M')` with the label `plaintext_number` as follows:" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "plaintext_number = alph.find('M')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Below, write ``plaintext_number`` in the code box, click Run, and verify that Sage spits out the number $12$." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 8, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "plaintext_number" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Here's our next step:\n", - "\n", - "2. To get a ciphertext number, shift the plaintext number up by 3, looping around so that, for example, Z is replaced with C. In other words, we're taking the plaintext number plus 3, mod 26, to get the ciphertext number. \n", - "\n", - "Sage also has this ability built-in. For example, to do 24 plus 3 mod 26, the code is ``Mod(24+3,26)``. The first thing after the parentheses is the number we want to reduce mod 26. The second number is the modulus. This gives us a ciphertext number.\n", - "\n", - "Below, write the code to add $3$ to the number $12$ mod $26$. In other words, we want to do $12+3\\mod{26}$. Then run your code. If it doesn't do what you expect, talk to a group member or your instructor." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "15" - ] - }, - "execution_count": 9, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "Mod(3+12,26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Because we'll be generalizing this code in a bit, let's replace that $12$ in your code above with the variable `plaintext_number`. In the box below, copy your code from above, but delete the $12$ and write `plaintext_number` in its place. (This will be useful later.)" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "15" - ] - }, - "execution_count": 10, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "Mod(3+plaintext_number,26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, just like we labeled $12$ with `plaintext_number`, we'll label the $15$ with `ciphertext_number`. Copy your code from the box above and paste it after the equals sign in the box below." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "ciphertext_number = Mod(3+plaintext_number,26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "3. Convert the ciphertext number to a ciphertext letter.\n", - "\n", - "Thankfully, Sage also has the ability to convert numbers to letters built-in. The command is ``alph``. So, for example, to convert the number 21 to a letter, we'd write ``alph[21]``.\n", - "\n", - "Below, write the code to convert our ciphertext number (which we conveniently labeled `ciphertext_number`) to a letter. In other words, replace the $21$ above with the variable `ciphertext_number`. If it doesn't do what you expect, talk to a group member or your instructor.\n", - "\n", - "It's useful to test code like this, doing a \"sanity check\". If you ask Python to compute $4+3\\mod{26}$ and it spits out $1$, you know something probably went wrong. Then you can go back to your code and try to fix it." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'P'" - ] - }, - "execution_count": 13, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "alph[ciphertext_number]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "In the box below, copy-paste your code from above, but this time label the resulting ciphertext letter with the variable `ciphertext_letter` so we can easily refer to it in the future." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "ciphertext_letter = alph[ciphertext_number]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "4. Append that letter to our output ciphertext.\n", - "\n", - "Remember that blank word we called ``ciphertext`` above? Here's where it comes in. We've converted the letter M to a number, shifted the number over by $3$, then converted the result back to a letter. If your code worked correctly, the resulting ciphertext letter should be P. (If you didn't get P, try looking over your code above again or asking someone.)\n", - "\n", - "We now want to store that P as the first letter of our ciphertext. Then we'll add other ciphertext letters one by one until our ciphertext is complete.\n", - "\n", - "In Python and Sage, adding things one by one is called *appending*. For example, the command to append the letter Q to the variable ``weirdletters`` is ``weirdletters += 'Q'``. The logic behind the `+=` is that we're first adding (`+`-ing) `Q` to the variable `weirdletters`, then we're *redefining* `weirdletters` to be itself plus `Q`. (Re)defining variables in Python is done with `=` signs. So together, we're doing both a `+` and an `=`, hence `+=`. (Don't worry, you won't be required to memorize this; you can always come back to this worksheet to remind yourself.)\n", - "\n", - "Below, write the code to append `ciphertext_letter` to the variable `ciphertext`. Then, in the next line, test your code by just writing the word ``ciphertext``. Sage should output `'P'` if your code works correctly." - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "'P'" - ] - }, - "execution_count": 15, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "ciphertext += ciphertext_letter\n", - "ciphertext" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Shifting Whole Words\n", - "\n", - "Great! You've managed to shift one plaintext letter to a ciphertext letter. However, in order to encrypt messages, we're going to need to shift *multiple* plaintext letters at once. To do this, we need the magic of ``for`` loops.\n", - "\n", - "You've already seen ``for`` loops in Codecademy. Basically, the idea is that we want to repeat a task, like shifting letters, over and over again. How many times do we want to repeat the task? Well, once for every letter in our plaintext. The code to start this ``for`` loop is\n", - "\n", - "``for letter in plaintext:``" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "If you type the above line of code into a code chunk and hit enter, the next line will be tabbed over. Python uses whitespace as a way of managing what's inside a `for` loop and what's not. **Everything you write that's tabbed over will be done for every single letter of your plaintext.** \n", - "\n", - "So what should we write tabbed over inside this `for` loop? I'm glad you asked. Once you've reached this point, try to help others around you until we're all at this point, and we'll talk as a class about what goes inside our `for` loop." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "### Let's do it!\n", - "\n", - "Are you back? Great! Let's try to write a `for` loop that encrypts the entire message 'MYSECRET' with a shift of $3$. \n", - "\n", - "Our goal is to replace the letter 'M' in our code above with a *variable*. Like in algebra, variables can take on many values. So far, we've already seen the variables ``alph``, ``plaintext``, ``key``, and ``ciphertext``. They are placeholders for letters or numbers that can be assigned values, just like the equation $x=3$ assigns the variable $x$ the value $3$.\n", - "\n", - "Below, I've started you off with the beginning of a `for` loop and the code we used to shift 'M' by $3$. There's an extra line at the bottom of the for loop which you don't need to worry about for now. Edit that code by deleting all references to 'M' and replacing them with the variable ``letter``. Then the `for` loop will cycle through all the letters in the message 'MYSECRET' and shift *all* of them by $3$. Then click Run on your edited chunk and see what happens. Once you click Run and observe the results, read the text below the chunk." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "plaintext = 'MYSECRET'\n", - "ciphertext = ''\n", - "key = 3\n", - "\n", - "for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(plaintext_number + 3, 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "If you edited and ran the code above correctly, *nothing should have happened*. Why not? Well, we didn't actually tell Sage to *show* us the ciphertext.\n", - "\n", - "This might sound silly. Computer programs and programming languages are very smart in some ways and very dumb in others. To a human, it'd be obvious that, if we asked them to convert plaintext to ciphertext, they should actually tell us what the ciphertext is. To Sage, not so much. We have to explicitly ask using the `print` command.\n", - "\n", - "The `print` command doesn't actually send anything to a printer. It just prints words, numbers, or letters on the screen. For example, see what happens when you run the code chunk below." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Hamsters!\n" - ] - } - ], - "source": [ - "print(\"Hamsters!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Seems pretty straightforward, right? Anything you put in the parentheses after `print` gets printed. Remember that if you want to print words, you have to enclose those words in apostrophes or quotation marks. However, to print a *variable*, you don't need the quotations. For example, if I had a variable `hamsters` which I set equal to $3$, then the command `print(hamsters)` should spit out the number $3$. \n", - "\n", - "Give it a try! In the chunk below, label the number $3$ with the variable `hamsters`. Then tell Sage to `print` the variable `hamsters`. If you don't get a $3$ out, recheck your code and/or talk to someone." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n" - ] - } - ], - "source": [ - "hamsters = 3\n", - "print hamsters" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now back to shift ciphers. We want to print the ciphertext, which we've conveniently assigned to the variable `ciphertext`. In the code box below, outside the tabbed section, write the command to print the variable `ciphertext`. Then run the chunk and see what happens. You should see the ciphertext resulting from encrypting the word 'MYSECRET' with the key $3$." - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PBVHFUHW\n" - ] - } - ], - "source": [ - "plaintext = 'MYSECRET'\n", - "ciphertext = ''\n", - "key = 3\n", - "\n", - "for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(plaintext_number + 3, 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - "print ciphertext" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Creating a Function\n", - "\n", - "Now, when shift ciphers are used in the real world, the plaintext is almost certain not to be 'MYSECRET', and the key may not be $3$. Instead of this specific plaintext and key, we want to allow ourselves the freedom to *define* whatever plaintext and key we want. In other words, we want ``plaintext`` and ``key`` to be *variables*.\n", - "\n", - "We can almost exactly recycle our code from above, where we encrypted 'MYSECRET' with a shift of $3$. However, we'll need to replace any references to specific plaintext with the variable `plaintext` and any references to specific numerical keys with the variable `key`. \n", - "\n", - "In the code box below, remove all references to the plaintext 'MYSECRET', leaving only references to the variable `plaintext`, and all references to the number $3$, leaving only references to the variable `key`. Then try running the chunk. Once you've run the chunk and observed what happens, read the text below." - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "PBVHFUHW\n" - ] - } - ], - "source": [ - "ciphertext = ''\n", - "\n", - "for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(plaintext_number + key, 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - "print(ciphertext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The chunk above should have again spit out the ciphertext corresponding to the plaintext 'MYSECRET'. This is because we've already told Python in the previous section that `plaintext` is a placeholder for the text 'MYSECRET' and `key` is a placeholder for the number $3$. What if we want to encrypt a different message using a different key? Do we have to write all this code out again, changing the values of the variables `plaintext` and `key`? Thankfully, no!\n", - "\n", - "To save us from having to write out all this code anytime we want to encrypt a message with a shift cipher, we'll wrap everything up in a **function**. Then, if we want to encrypt the message 'POTATO' using the key $7$, all we'll have to write is\n", - "\n", - "``ShiftEncrypt('POTATO',7)``\n", - "\n", - "Just like a mathematical function like $f(x)=3x+2$, Sage functions have *inputs* or *independent variables* (like $x$ in the example $f(x)=3x+2$) and *outputs* or *dependent variables* (like the $3x+2$). For every input $x$ (for example $x=3$), the function outputs $3$ times that input plus $2$. So for the input $3$, the function $f(x)$ spits out $11$.\n", - "\n", - "The function we're dealing with doesn't just have one input, though, it has two: the plaintext and the key. One of those inputs (the plaintext) is a word and the other is a number.\n", - "\n", - "Remember from Codecademy that, to start defining a Sage or Python function, you have to start with a `def` command. I'll set the `def` command up for you below; try copy-pasting your code from the chunk above underneath the `def` command. Remember that everything the function does has to be tabbed over once, and everything in your `for` loop has to be tabbed over once more, so the stuff inside your `for` loop is *double*-tabbed! I\"ll start you off by defining the alphabet and the empty string called `ciphertext` like we did above." - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def ShiftEncrypt(plaintext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " ciphertext = ''\n", - " for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(plaintext_number + key, 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - " print(ciphertext)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, mimic my code in the 'POTATO' example above and use your function to encrypt the word 'STARGAZER' with a shift of $17$. Yes, it was a lot of work to write the function, but now that we have the function, encryption is so much easier than it would be by hand!" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "JKRIXRQVI\n" - ] - } - ], - "source": [ - "ShiftEncrypt('STARGAZER',17)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Exercises\n", - "\n", - "Now that you have a function, try answering the following:\n", - "\n", - "1. What do you think happens if you try to use a key that's larger than your alphabet? Try encoding a message with a shift of 27 and see! Is the result what you expected? Can you do some modular arithmetic to show why this is the case?" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "NPOLFZ\n" - ] - } - ], - "source": [ - "ShiftEncrypt(\"MONKEY\", 27)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The alphabet \"rolls over\" or \"starts over\" again. For example, shifting by 27 is the same as shifting by 1." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "2. Finally, copy and paste the function above (changing the function's name) and try to change the code so that it encrypts using a larger alphabet of your choice. For example, you could add the special characters ~!? to your alphabet. Be sure to adjust the modulus accordingly!" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def ShiftEncryptX(plaintext, key):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ~?!'\n", - " ciphertext = ''\n", - " for letter in plaintext:\n", - " plaintext_number = alph.find(letter)\n", - " ciphertext_number = Mod(plaintext_number + key, 29)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - " print(ciphertext)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "KMLICW\n" - ] - } - ], - "source": [ - "ShiftEncryptX(\"MONKEY\",27)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, a shift of 27 really is different from a shift of anything less than 27." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/VigenereEncrypt-1.ipynb b/Python Modules/*Python Module Rubrics/VigenereEncrypt-1.ipynb deleted file mode 100755 index 8b4af35..0000000 --- a/Python Modules/*Python Module Rubrics/VigenereEncrypt-1.ipynb +++ /dev/null @@ -1,604 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Vigenère Encryption\n", - "\n", - "All of the ciphers we've seen up to this point have been **monoalphabetic substitution ciphers**, meaning they use only one *cipher alphabet* (way of assigning a given plaintext letter to a ciphertext letter). Today, we'll work with a **polyalphabetic substitution cipher** for the first time, where (for example) a plaintext $e$ could be enciphered either as a ciphertext $O$ or a ciphertext $A$.\n", - "\n", - "As usual, we'll start by telling Python that we're working with capital English letters. Run the chunk below to do this:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "As before, our first step is to take a given plaintext letter and convert it to a number. Do you remember what code does this? Copy/paste the code from your `ShiftEncrypt` function that changes plaintext letters to plaintext numbers and labels the number `plaintext_number`. **Don't run the code yet.**" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "plaintext_number = alph.find(letter)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The genius of Vigenère is that it uses a *keyword* to cycle between **multiple** shifts, so that a Vigenère cipher is actually multiple shift ciphers that we cycle through (like you cycled through two shifts in your reading question). Any idea how we could use a keyword to encode shifts? Write your answer below." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Just like we converted the plaintext to numbers, we need to convert the key to numbers as well. Below, write the code that would convert the variable `keyword` to numbers and label it `key_numbers`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "key_numbers = alph.find(keyword)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Vigenère cycles between shifts in the following way. \n", - "\n", - "1. First off, the keyword is spelled out above the message, and repeated over and over again so that each letter in the message is associated with a letter from the keyword: \n", - "
\n",
-    "Plaintext: d i v e r t t r o o p s t o e a s t r i d g e\n",
-    "Keyword:   W H I T E W H I T E W H I T E W H I T E W H I\n",
-    "
\n", - "2. To encrypt the first letter, we note that the plaintext 'd' lines up with the keyword 'W'. This means that we'll shift the 'd' forward by the amount encoded by 'W'.\n", - "\n", - "What does W correspond to in our letter-to-number chart, and what would be the result of shifting a 'd' forward by that number?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Similarly, since the plaintext 'i' aligns with the keyword 'H', we want to shift the 'i' forward by the amount encoded by the 'H'. What is that shift, and what is the result of shifting 'i' forward by this amount?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Since the key is repeated over and over again under the plaintext, it's important that we know the length of the keyword. \n", - "\n", - "In Python, the code to output the length of a string (such as a keyword) is `len(string)`. For example, to find the length of the word \"ALLIGATOR\", we'd type\n", - "\n", - "
\n",
-    "len('ALLIGATOR')\n",
-    "
\n", - "\n", - "Below, write the code to find the length of the word \"SUPERCALIFRAGILISTICEXPIALIDOCIOUS\". In the second code chunk below, write the code to find the length of the variable `alph`, which we've assigned to the English alphabet." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "34" - ] - }, - "execution_count": 4, - "metadata": { - }, - "output_type": "execute_result" - } - ], - "source": [ - "len('SUPERCALIFRAGILISTICEXPIALIDOCIOUS')" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Were the outputs of the `len` functions above what you expected? Why or why not?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, we'll assign the length of our `keyword` to the variable `key_length`. Write the code to output the length of the variable `keyword` and assign it to the name `key_length` using code below (don't run it):" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "key_length = len(keyword)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Continuing our steps for enciphering using Vigenere, the next step is to add the amount of the keyword shift to the plaintext, just as you did with the plaintext 'd' and 'i' in \"divert troops to east ridge\".\n", - "\n", - "You've already written the code to convert both the plaintext to a number (`plaintext_number`) and the keyword to numbers (`key_number`). Below, write the code to add `key_number` to `plaintext_number` $\\mod{26}$ (but **don't run it**)." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "Mod(key_number + plaintext_number, 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to start with an empty string of ciphertext (`''`) and add the corresponding keyword number to every plaintext number. Since we're repeating the step of adding the key letter to the plaintext letter for every letter in the plaintext, we'll need to use a `for` loop!\n", - "\n", - "Remember how we used code like `alph[3]` to find the third letter in the alphabet? That code really treated `alph` as a string and searched for the third character (i.e., letter) in the string, then output that letter. \n", - "\n", - "How do you think we would output the zeroth (remember Python lists start at zero) letter in the string `keyword`? Write that code below (don't run it):" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "keyword[0]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, we're ready to encipher a single plaintext letter! We want to perform the following steps:\n", - "\n", - "1. Define `alph` to be the capital English alphabet.\n", - "2. Assign the length of the variable `keyword` to the variable `key_length`.\n", - "3. Start with an empty string of ciphertext.\n", - "4. Convert the first letter of the string `plaintext` to a number and call the result `plaintext_number`.\n", - "5. Convert the first letter of the string `keyword` to a number and call the result `key_number`.\n", - "6. Add the `key_number` to the `plaintext_number`, mod $26$, and call the result `ciphertext_number`.\n", - "7. Convert the `ciphertext_number` back to a `ciphertext_letter`.\n", - "8. Add `ciphertext_number` to the string `ciphertext`.\n", - "\n", - "Almost all these steps are things we've done before in previous modules (e.g., converting letters to numbers and vice versa). Below, write the code to label the empty string `''` with the name `ciphertext`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "ciphertext = ''" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to do this for every plaintext letter and the corresponding keyword letter using a `for` loop. Here's a shortcut: the code\n", - "\n", - "
\n",
-    "(1.2)\n",
-    "key_numbers = [alph.find(i) for i in keyword]\n",
-    "
\n", - "\n", - "turns every letter in the keyword into a number and stores the entire result in the string `key_numbers`. So, for example, if the keyword was \"HI\", `key_numbers` would be `[7, 8]` because $H=7$ and $I=8$ in our letter-to-number chart.\n", - "\n", - "Below, write the code to convert the entire plaintext to numbers and call the result `plaintext_numbers` (mimic the `key_numbers` code above but change the names)." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.3)\n", - "plaintext_numbers = [alph.find(i) for i in plaintext]" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to tell Python to repeat the keyword numbers over and over again under the plaintext numbers. For example, if the keyword is \"NICE\" and the plaintext is \"FIREFIGHTER\", we'd do the following:\n", - "\n", - "1. Convert both to numbers like you did above:\n", - "
\n",
-    "Plaintext:\n",
-    "  \n",
-    "  F  I  R  E  F  I  G  H  T  E  R\n",
-    "  5  8  17 4  5  8  6  7  19 4  17\n",
-    "\n",
-    "Key:\n",
-    "\n",
-    "  N  I  C  E  N  I  C  E  N  I  C\n",
-    "  13 8  2  4  13 8  2  4  13 8  2\n",
-    "
\n", - "\n", - "2. Repeat the key over and over again under the plaintext, then add corresponding key letters to corresponding plaintext letters:\n", - "\n", - "
\n",
-    "Plaintext:\n",
-    "  \n",
-    "  F  I  R  E  F  I  G  H  T  E  R\n",
-    "  5  8  17 4  5  8  6  7  19 4  17\n",
-    "\n",
-    "Key:\n",
-    "\n",
-    "  N  I  C  E  N  I  C  E  N  I  C\n",
-    "+ 13 8  2  4  13 8  2  4  13 8  2\n",
-    "  ----------\n",
-    "  18 16 19 8  18 16 8  11 ...\n",
-    "  \n",
-    "
\n", - "\n", - "How do we tell Python to do this? Well, note that we're adding the first letter of the keyword to the first, fifth, and ninth letters of the plaintext (F, F, T). The length of the keyword here is 4. What time do 1, 5, and 9 all represent on a 4-hour clock?" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "Answer here" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "So to figure out what key letter to add to a given plaintext letter, we just reduce the position of the plaintext letter modulo the key letter! For example, since 'I' is the sixth letter of 'FIREFIGHTER', we'd add the \n", - "\n", - "$$\n", - "6\\mod{4} \\equiv 2\\text{nd}\n", - "$$\n", - "\n", - "letter of the key to 'I'.\n", - "\n", - "Below, I'll write the code to do this to the $i$th letter of `plaintext_numbers`, reduce mod 26, and label the result `ciphertext_number`. (Don't run it yet.)" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.4)\n", - "\n", - "ciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We want to do the process in chunk (1.4) to every letter of the plaintext. This requires us to use a for loop that begins\n", - "\n", - "``\n", - "for i in range(len(plaintext_numbers)):\n", - "``\n", - "\n", - "Let's break this down. The string `plaintext_numbers` is a list of numbers. Its length is the same as the length of the plaintext, one plaintext number for every plaintext letter. \n", - "\n", - "This `for` loop will start with the zeroth (remember all Python lists start at 0) plaintext number, then move on to the first, then the second, and so on until it reaches the length of the plaintext. This is exactly what we want to do in order to encrypt a message!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, we're ready! Copy-paste lines (1.1), (1.2), and (1.3) of code in the chunk below. Below those, copy-paste the beginning of the `for` loop. Finally, tabbed over underneath the `for` command, copy-paste line (1.4) of code. Finally, still underneath the `for` loop, add code to convert `ciphertext_number` back to `ciphertext_letter` and append the result to the end of the string `ciphertext`. Then, outside the loop, have Python print the ciphertext." - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def VigenereEncrypt(plaintext, keyword):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " ciphertext = ''\n", - " plaintext_numbers = [alph.find(i) for i in plaintext]\n", - " key_numbers = [alph.find(i) for i in keyword]\n", - " for i in range(len(plaintext_numbers)):\n", - " ciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)\n", - " ciphertext_letter = alph[ciphertext_number]\n", - " ciphertext += ciphertext_letter\n", - " print ciphertext" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Exercises\n", - "\n", - "1. Test your shiny new function by encrypting two or three lines of lyrics by one of your favorite artists using the keyword 'MUSIC'." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "2. What do you think would happen if you encrypted a Vigenère message using a key with only one letter (e.g. 'B')? Try encrypting the same message from Exercise 1 with the keyword 'B'. What happened? How secure is this cipher?" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Explain what happened here." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "3. Encrypt a reasonably-long message using a key of length 2 below. Then share the ciphertext with a partner at your table and see if they can break it!" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "4. Write a Vigenère **decryption** function by reversing the roles of ciphertext and plaintext in the chunk above where you defined the `VigenereEncrypt` function and changing only one other symbol in the code." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "def VigenereDecrypt(ciphertext, keyword):\n", - " " - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "5. Test your Vigenère decryption function by using it to decrypt your ciphertext from Exercise 1." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "SageMath 9.1", - "language": "sagemath", - "metadata": { - "cocalc": { - "description": "Open-source mathematical software system", - "priority": 1, - "url": "https://www.sagemath.org/" - } - }, - "name": "sage-9.1", - "resource_dir": "/ext/jupyter/kernels/sage-9.1" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.3" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/*Python Module Rubrics/VigenereEncrypt-Rubric.ipynb b/Python Modules/*Python Module Rubrics/VigenereEncrypt-Rubric.ipynb deleted file mode 100755 index daa29dd..0000000 --- a/Python Modules/*Python Module Rubrics/VigenereEncrypt-Rubric.ipynb +++ /dev/null @@ -1,621 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "# Vigenère Encryption Rubric (only grade bottom function and exercises)\n", - "\n", - "All of the ciphers we've seen up to this point have been **monoalphabetic substitution ciphers**, meaning they use only one *cipher alphabet* (way of assigning a given plaintext letter to a ciphertext letter). Today, we'll work with a **polyalphabetic substitution cipher** for the first time, where (for example) a plaintext $e$ could be enciphered either as a ciphertext $O$ or a ciphertext $A$.\n", - "\n", - "As usual, we'll start by telling Python that we're working with capital English letters. Run the chunk below to do this:" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "As before, our first step is to take a given plaintext letter and convert it to a number. Do you remember what code does this? Copy/paste the code from your `ShiftEncrypt` function that changes plaintext letters to plaintext numbers and labels the number `plaintext_number`. **Don't run the code yet.**" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "The genius of Vigenère is that it uses a *keyword* to cycle between **multiple** shifts, so that a Vigenère cipher is actually multiple shift ciphers that we cycle through (like you cycled through two shifts in your reading question). Any idea how we could use a keyword to encode shifts? Write your answer below." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Just like we converted the plaintext to numbers, we need to convert the key to numbers as well. Below, write the code that would convert the variable `keyword` to numbers and label it `key_numbers`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Vigenère cycles between shifts in the following way. \n", - "\n", - "1. First off, the keyword is spelled out above the message, and repeated over and over again so that each letter in the message is associated with a letter from the keyword: \n", - "
\n",
-    "Plaintext: d i v e r t t r o o p s t o e a s t r i d g e\n",
-    "Keyword:   W H I T E W H I T E W H I T E W H I T E W H I\n",
-    "
\n", - "2. To encrypt the first letter, we note that the plaintext 'd' lines up with the keyword 'W'. This means that we'll shift the 'd' forward by the amount encoded by 'W'.\n", - "\n", - "What does W correspond to in our letter-to-number chart, and what would be the result of shifting a 'd' forward by that number?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Similarly, since the plaintext 'i' aligns with the keyword 'H', we want to shift the 'i' forward by the amount encoded by the 'H'. What is that shift, and what is the result of shifting 'i' forward by this amount?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Since the key is repeated over and over again under the plaintext, it's important that we know the length of the keyword. \n", - "\n", - "In Python, the code to output the length of a string (such as a keyword) is `len(string)`. For example, to find the length of the word \"ALLIGATOR\", we'd type\n", - "\n", - "
\n",
-    "len('ALLIGATOR')\n",
-    "
\n", - "\n", - "Below, write the code to find the length of the word \"SUPERCALIFRAGILISTICEXPIALIDOCIOUS\". In the second code chunk below, write the code to find the length of the variable `alph`, which we've assigned to the English alphabet." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Were the outputs of the `len` functions above what you expected? Why or why not?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Finally, we'll assign the length of our `keyword` to the variable `key_length`. Write the code to output the length of the variable `keyword` and assign it to the name `key_length` using code below (don't run it):" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.1)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Continuing our steps for enciphering using Vigenere, the next step is to add the amount of the keyword shift to the plaintext, just as you did with the plaintext 'd' and 'i' in \"divert troops to east ridge\".\n", - "\n", - "You've already written the code to convert both the plaintext to a number (`plaintext_number`) and the keyword to numbers (`key_number`). Below, write the code to add `key_number` to `plaintext_number` $\\mod{26}$ (but **don't run it**)." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to start with an empty string of ciphertext (`''`) and add the corresponding keyword number to every plaintext number. Since we're repeating the step of adding the key letter to the plaintext letter for every letter in the plaintext, we'll need to use a `for` loop!\n", - "\n", - "Remember how we used code like `alph[3]` to find the third letter in the alphabet? That code really treated `alph` as a string and searched for the third character (i.e., letter) in the string, then output that letter. \n", - "\n", - "How do you think we would output the zeroth (remember Python lists start at zero) letter in the string `keyword`? Write that code below (don't run it):" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, we're ready to encipher a single plaintext letter! We want to perform the following steps:\n", - "\n", - "1. Define `alph` to be the capital English alphabet.\n", - "2. Assign the length of the variable `keyword` to the variable `key_length`.\n", - "3. Start with an empty string of ciphertext.\n", - "4. Convert the first letter of the string `plaintext` to a number and call the result `plaintext_number`.\n", - "5. Convert the first letter of the string `keyword` to a number and call the result `key_number`.\n", - "6. Add the `key_number` to the `plaintext_number`, mod $26$, and call the result `ciphertext_number`.\n", - "7. Convert the `ciphertext_number` back to a `ciphertext_letter`.\n", - "8. Add `ciphertext_number` to the string `ciphertext`.\n", - "\n", - "Almost all these steps are things we've done before in previous modules (e.g., converting letters to numbers and vice versa). Below, write the code to label the empty string `''` with the name `ciphertext`." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.1)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to do this for every plaintext letter and the corresponding keyword letter using a `for` loop. Here's a shortcut: the code\n", - "\n", - "
\n",
-    "(1.2)\n",
-    "key_numbers = [alph.find(i) for i in key]\n",
-    "
\n", - "\n", - "turns every letter in the keyword into a number and stores the entire result in the string `key_numbers`. So, for example, if the keyword was \"HI\", `key_numbers` would be `[7, 8]` because $H=7$ and $I=8$ in our letter-to-number chart.\n", - "\n", - "Below, write the code to convert the entire plaintext to numbers and call the result `plaintext_numbers` (mimic the `key_numbers` code above but change the names)." - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.3)\n" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "Now, we want to tell Python to repeat the keyword numbers over and over again under the plaintext numbers. For example, if the keyword is \"NICE\" and the plaintext is \"FIREFIGHTER\", we'd do the following:\n", - "\n", - "1. Convert both to numbers like you did above:\n", - "
\n",
-    "Plaintext:\n",
-    "  \n",
-    "  F  I  R  E  F  I  G  H  T  E  R\n",
-    "  5  8  17 4  5  8  6  7  19 4  17\n",
-    "\n",
-    "Key:\n",
-    "\n",
-    "  N  I  C  E  N  I  C  E  N  I  C\n",
-    "  13 8  2  4  13 8  2  4  13 8  2\n",
-    "
\n", - "\n", - "2. Repeat the key over and over again under the plaintext, then add corresponding key letters to corresponding plaintext letters:\n", - "\n", - "
\n",
-    "Plaintext:\n",
-    "  \n",
-    "  F  I  R  E  F  I  G  H  T  E  R\n",
-    "  5  8  17 4  5  8  6  7  19 4  17\n",
-    "\n",
-    "Key:\n",
-    "\n",
-    "  N  I  C  E  N  I  C  E  N  I  C\n",
-    "+ 13 8  2  4  13 8  2  4  13 8  2\n",
-    "  ----------\n",
-    "  18 16 19 8  18 16 8  11 ...\n",
-    "  \n",
-    "
\n", - "\n", - "How do we tell Python to do this? Well, note that we're adding the first letter of the keyword to the first, fifth, and ninth letters of the plaintext (F, F, T). The length of the keyword here is 4. What time do 1, 5, and 9 all represent on a 4-hour clock?" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "So to figure out what key letter to add to a given plaintext letter, we just reduce the position of the plaintext letter modulo the key letter! For example, since 'I' is the sixth letter of 'FIREFIGHTER', we'd add the \n", - "\n", - "$$\n", - "6\\mod{4} \\equiv 2\\text{nd}\n", - "$$\n", - "\n", - "letter of the key to 'I'.\n", - "\n", - "Below, I'll write the code to do this to the $i$th letter of `plaintext_numbers`, reduce mod 26, and label the result `ciphertext_number`. (Don't run it yet.)" - ] - }, - { - "cell_type": "code", - "execution_count": 0, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "(1.4)\n", - "\n", - "ciphertext_number = Mod(plaintext_numbers[i] + key_numbers[i % key_length], 26)" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "We want to do the process in chunk (1.4) to every letter of the plaintext. This requires us to use a for loop that begins\n", - "\n", - "``\n", - "for i in range(len(plaintext_numbers)):\n", - "``\n", - "\n", - "Let's break this down. The string `plaintext_numbers` is a list of numbers. Its length is the same as the length of the plaintext, one plaintext number for every plaintext letter. \n", - "\n", - "This `for` loop will start with the zeroth (remember all Python lists start at 0) plaintext number, then move on to the first, then the second, and so on until it reaches the length of the plaintext. This is exactly what we want to do in order to encrypt a message!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "OK, we're ready! Copy-paste lines (1.1), (1.2), and (1.3) of code in the chunk below. Below those, copy-paste the beginning of the `for` loop. Finally, tabbed over underneath the `for` command, copy-paste line (1.4) of code. Finally, still underneath the `for` loop, add code to convert `ciphertext_number` back to `ciphertext_letter` and append the result to the end of the string `ciphertext`. Then, outside the loop, have Python print the ciphertext." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Define a Vigenere encryption function\n", - "def VigenereEncrypt(plaintext, keyword):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " key_length = len(keyword)\n", - "# Convert the key and plaintext from letters to numbers\n", - " key_numbers = [alph.find(i) for i in keyword]\n", - " plaintext_numbers = [alph.find(i) for i in plaintext]\n", - "# Start with an empty string of ciphertext\n", - " ciphertext = ''\n", - "# Write the key over and over again underneath the plaintext, then add the two together and reduce modulo 26. Finally, convert the ciphertext numbers to letters and return the result.\n", - " for i in range(len(plaintext_numbers)):\n", - " ciphertext_number = (plaintext_numbers[i] + key_numbers[i % key_length]) % 26\n", - " ciphertext_letter = alph[ciphertext_ ciphertext += ciphertext_letter\n", - " print ciphertext" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "## Exercises\n", - "\n", - "1. Test your shiny new function by encrypting two or three lines of lyrics by one of your favorite artists using the keyword 'MUSIC'." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "RLALCKZJQFMSYWVFUYMVPIOVQZZJQFMS\n" - ] - } - ], - "source": [ - "VigenereEncrypt(\"FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\", \"MUSIC\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "2. What do you think would happen if you encrypted a Vigenère message using a key with only one letter (e.g. 'A')? Try encrypting the same message from Exercise 1 with the keyword 'B'. What happened? How secure is this cipher?" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "GSJEBZGSJEBZHPUUBHFUEPXOPOGSJEBZ\n" - ] - } - ], - "source": [ - "VigenereEncrypt(\"FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\", \"B\")" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "This is just a shift cipher with shift $B=+1$. This is not secure at all since it is vulnerable to frequency analysis and brute force." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "3. Encrypt a reasonably-long message using a key of length 2 below. Then share the ciphertext with a partner at your table and see if they can break it!" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "HRWCNSGJOXNOLKAZZONYTJOJJSUOBOFONOBMFIDDSNNWSCGKUO\n" - ] - } - ], - "source": [ - "VigenereEncrypt('THIS IS AN EXAMPLE OF A VIGENERE ENCRYPTED MESSAGE', 'OK')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "4. Write a Vigenère **decryption** function by reversing the roles of ciphertext and plaintext in the chunk above where you defined the `VigenereEncrypt` function and changing only one other symbol in the code." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - ], - "source": [ - "# Define a Vigenere decryption function\n", - "def VigenereDecrypt(ciphertext, keyword):\n", - " alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'\n", - " key_length = len(keyword)\n", - "# Convert the key and ciphertext from letters to numbers\n", - " key_numbers = [alph.find(i) for i in keyword]\n", - " ciphertext_numbers = [alph.find(i) for i in ciphertext]\n", - "# Start with an empty string of plaintext\n", - " plaintext = ''\n", - "# Write the key over and over again underneath the ciphertext, then subtract the key from the ciphertext and reduce modulo 26. Finally, convert the plaintext numbers to letters and return the result.\n", - " for i in range(len(ciphertext_numbers)):\n", - " plaintext_number = (ciphertext_numbers[i] - key_numbers[i % key_length]) % 26\n", - " plaintext_letter = alph[plaintext_number]\n", - " plaintext += plaintext_letter\n", - " print plaintext" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "collapsed": false - }, - "source": [ - "5. Test your Vigenère decryption function by using it to decrypt your ciphertext from Exercise 1." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "FRIDAYFRIDAYGOTTAGETDOWNONFRIDAY\n" - ] - } - ], - "source": [ - "VigenereDecrypt('RLALCKZJQFMSYWVFUYMVPIOVQZZJQFMS', \"MUSIC\")" - ] - } - ], - "metadata": { - "kernelspec": { - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.15" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} \ No newline at end of file diff --git a/Python Modules/.DS_Store b/Python Modules/.DS_Store index 29c06a6..b592ee1 100755 Binary files a/Python Modules/.DS_Store and b/Python Modules/.DS_Store differ