#| The Imitation Game Lab. This lab is about encryption. Your goal is to decrypt the following two secret messages. Make sure you are in ACL2s mode. |# ; This is how we define constants in ACL2s. ; This is an encoded message. (defconst *code1* '((NIL NIL NIL NIL NIL) (T NIL T NIL NIL) (T NIL T T T) (NIL T NIL NIL T) (NIL NIL NIL T T) (NIL NIL T T T) (T T NIL T T) (T NIL NIL NIL T) (T T NIL NIL T) (NIL T NIL NIL T) (T NIL NIL T NIL) (NIL NIL NIL T NIL) (T T T NIL T) (NIL NIL T NIL T) (T T T T NIL) (NIL T NIL NIL T) (T NIL T T NIL) (T T T NIL T) (NIL NIL T NIL NIL) (NIL T NIL NIL T) (T T NIL T NIL) (NIL NIL T T T) (T T T T T) (T T T NIL NIL) (T NIL T T T) (T NIL NIL NIL NIL) (NIL T NIL NIL T) (T T T NIL T) (NIL NIL T T NIL) (T NIL T T T) (NIL NIL NIL T NIL) (NIL T NIL NIL T) (NIL NIL NIL NIL NIL) (T NIL T NIL NIL) (T NIL T T T) (NIL T NIL NIL T) (T T NIL NIL NIL) (T NIL NIL T T) (NIL T NIL T NIL) (NIL T NIL T T) (NIL T NIL NIL T) (T NIL NIL NIL NIL) (T T T NIL T) (T NIL T NIL T) (NIL T T T NIL) (NIL NIL NIL NIL T) (NIL T NIL NIL T) (T NIL NIL T NIL) (T NIL NIL T T) (T NIL NIL NIL T) (T T NIL NIL T))) ; A second encoded message. (defconst *code2* '((T NIL NIL T NIL) (T NIL NIL NIL T) (NIL NIL T NIL NIL) (T NIL NIL NIL T) (NIL T NIL NIL NIL) (NIL NIL T T T) (NIL T T T T) (T NIL NIL T NIL) (T NIL NIL NIL T) (NIL NIL T NIL NIL) (T NIL NIL NIL T) (NIL T NIL NIL NIL) (NIL NIL T T T) (NIL T T T T) (NIL NIL T T NIL) (T NIL NIL T NIL) (T NIL NIL NIL T) (NIL T T T T) (T NIL T NIL T) (T T NIL NIL NIL) (NIL NIL T T T) (NIL NIL NIL T T) (T NIL NIL NIL T) (NIL NIL T NIL NIL) (NIL T T T T) (NIL NIL T T NIL) (T T NIL T T) (NIL T T T T) (NIL NIL T T NIL) (T NIL NIL T NIL) (T NIL NIL NIL T) (NIL T T T T) (T T NIL NIL NIL) (T NIL NIL NIL T) (NIL NIL NIL T NIL) (NIL NIL T T NIL) (NIL T T T T) (NIL NIL T NIL T) (NIL NIL NIL NIL T) (T T T NIL T) (NIL T T NIL NIL) (NIL T T T T) (NIL T NIL T T) (T NIL T T NIL) (T NIL NIL NIL T) (T NIL NIL NIL NIL) (T T T NIL T) (T T NIL NIL NIL) (T NIL NIL NIL T) (T NIL T T T) (NIL T T T T) (T NIL T NIL T) (T NIL T NIL T) (T T NIL T NIL) (T T NIL T NIL) (NIL T T T T) (NIL T NIL T T) (NIL NIL NIL T NIL) (NIL T T T T) (NIL T T T NIL) (NIL NIL T T NIL) (T T T T NIL) (NIL T T T T) (NIL T T NIL T) (NIL T T T T) (NIL T T T NIL) (NIL NIL T T NIL) (T T T T NIL) (NIL T NIL T NIL) (NIL T T T T) (NIL T T T NIL) (NIL NIL T T NIL) (T T T T NIL) (NIL T T T T) (NIL T NIL T T) (T T T NIL T) (T NIL NIL NIL NIL) (NIL T T T T) (NIL T NIL T T) (T NIL NIL NIL T) (T T NIL NIL NIL) (T NIL T T NIL) (T T NIL T NIL) (NIL T T T T) (NIL NIL NIL T NIL) (NIL T NIL T NIL) (NIL T T T T) (NIL T T NIL T) (NIL T T T T) (NIL T NIL T T) (T NIL T T T) (T T NIL T T) (T T NIL NIL NIL) (NIL NIL T T T) (NIL T T T T) (NIL T NIL T T) (T NIL NIL NIL NIL) (T T T NIL T) (NIL NIL T NIL NIL) (NIL NIL T T T) (NIL NIL T T NIL) (NIL T T T T) (NIL NIL NIL T NIL) (NIL T NIL T NIL) (NIL T T T T) (NIL T NIL T T) (T NIL T NIL T) (T NIL T NIL T) (T T NIL T NIL) (T T NIL T NIL) (NIL T T T T) (NIL T NIL T T) (NIL NIL T NIL NIL) (T NIL NIL NIL T) (NIL NIL T T T) (NIL NIL T T NIL) (NIL T T T T) (NIL NIL NIL T NIL) (NIL T NIL T NIL) (NIL T T T T) (NIL T T NIL T) (NIL T NIL T NIL) (NIL T NIL T NIL) (NIL T NIL T NIL) (NIL T NIL T NIL))) ; Let's not worry about failed proofs, so as per the lecture ; notes, we will not require ACL2s to prove function and body ; contracts and we don't want defunc and testing to take more ; than 5 seconds. ; ; You may see some warnings here and there. Just ignore them. As ; long as the output is green, you are good to go. (set-defunc-termination-strictp nil) (set-defunc-function-contract-strictp nil) (set-defunc-body-contracts-strictp nil) (set-defunc-timeout 3) (acl2s-defaults :set cgen-timeout 1) #| How are we going to decode the encrypted message? Well, notice that each encrypted message consists of a list of lists of Booleans, each of length 5. That is because each list of Booleans corresponds to a character, as follows. |# ; This is a data definition for a list of exactly 5 Booleans. ; The name bv is an abbreviation of BitVector. (defdata bv (list boolean boolean boolean boolean boolean)) ; This is a data definition for 32 characters. (defdata char (enum '(#\A #\B #\C #\D #\E #\F #\G #\H #\I #\J #\K #\L #\M #\N #\O #\P #\Q #\R #\S #\T #\U #\V #\W #\X #\Y #\Z #\Space #\: #\- #\' #\( #\)))) ; We want a mapping (function) between char and bv. Since char is ; finite, we will use an alist. Here is the data definition (defdata char-bv (alistof char bv)) ; This is our mapping from chars to bvs. (defconst *bv-char-map* '((#\A . (nil nil nil nil nil)) (#\B . (nil nil nil nil t)) (#\C . (nil nil nil t nil)) (#\D . (nil nil nil t t)) (#\E . (nil nil t nil nil)) (#\F . (nil nil t nil t)) (#\G . (nil nil t t nil)) (#\H . (nil nil t t t)) (#\I . (nil t nil nil nil)) (#\J . (nil t nil nil t)) (#\K . (nil t nil t nil)) (#\L . (nil t nil t t)) (#\M . (nil t t nil nil)) (#\N . (nil t t nil t)) (#\O . (nil t t t nil)) (#\P . (nil t t t t)) (#\Q . (t nil nil nil nil)) (#\R . (t nil nil nil t)) (#\S . (t nil nil t nil)) (#\T . (t nil nil t t)) (#\U . (t nil t nil nil)) (#\V . (t nil t nil t)) (#\W . (t nil t t nil)) (#\X . (t nil t t t)) (#\Y . (t t nil nil nil)) (#\Z . (t t nil nil t)) (#\Space . (t t nil t nil)) (#\: . (t t nil t t)) (#\- . (t t t nil nil)) (#\' . (t t t nil t)) (#\( . (t t t t nil)) (#\) . (t t t t t)))) ; Let's check that *bv-char-map* is really a char-bvp (check= (char-bvp *bv-char-map*) t) ; Define a function that given an element a and an alist l returns ; the cons that has a as its car or nil if no such cons exists. (definec find-car (a :all l :alist) :list ...) (check= (find-car #\W *bv-char-map*) '(#\W . (t nil t t nil))) ; Define a function that given an element a and an alist l returns ; the cons that has a as its cdr or nil if no such pair exists. (definec find-cdr (a :all l :alist) :list ...) (check= (find-cdr '(t nil t t nil) *bv-char-map*) '(#\W . (t nil t t nil))) ; Next we want to define functions that given a char return the ; corresponding bv and the other way around. Define these ; functions. (definec char-bv (c :char) :bv ...) (check= (char-bv #\W) '(t nil t t nil)) (definec bv-char (b :bv) :char ...) (check= (bv-char '(t nil t t nil)) #\W) ; Next we have data definitions for a listof bvs and chars. ; This allows us to construct messages out of characters or out ; of bit vectors. (defdata lobv (listof bv)) (defdata lochar (listof char)) ; Here is a definition for a list of booleans. (defdata lob (listof boolean)) ; xor is a builtin function. ; Here is a function that xor's bit vectors. ; The contracts are a little more complicated than we usually ; write, but we really do want that lengths of the input bit ; vectors to be equal. (defunc xor-bv (b1 b2) :input-contract (and (lobp b1) (lobp b2) (equal (len b1) (len b2))) :output-contract (and (lobp (xor-bv b1 b2)) (equal (len (xor-bv b1 b2)) (len b1))) (if (endp b1) nil (cons (xor (first b1) (first b2)) (xor-bv (rest b1) (rest b2))))) ; Next we have a test? for sanity checking that claims that if we ; apply xor-bv on bv's then we get bv's back. (test? (implies (and (bvp b1) (bvp b2)) (bvp (xor-bv b1 b2)))) ; Ignore this (in-theory (disable charp bvp xor-bv-definition-rule bv-char-definition-rule char-bv-definition-rule)) ; Now let's define a function to encrypt a single character, ; given a bitvector. (definec encrypt-char (c :char s :bv) :bv ...) (check= (encrypt-char #\B '(t nil t nil t)) '(t nil t nil nil)) ; Ignore this (in-theory (disable encrypt-char-definition-rule)) ; Now, let's define a function to encrypt a message based on the ; lecture notes on one-time pads (the "power of xor") (defunc encrypt (m s) :input-contract (and (locharp m) (lobvp s) (equal (len m) (len s))) :output-contract (and (lobvp (encrypt m s)) (equal (len (encrypt m s)) (len m))) ...) ; Here is a function that makes a list containing n copies of e. (definec copy (e :all n :nat) :tl (if (equal n 0) nil (cons e (copy e (- n 1))))) ; Here are our (really bad!) keys. ; They are really bad because they should be a random sequence ; of bit vectors! (defconst *secret1* (copy '(t nil nil t t) (len *code1*))) (defconst *secret2* (copy '(t nil t nil t) (len *code2*))) ; Here is how we write a function to decode a bv c using the ; secret s. (definec decrypt-bv (c :bv s :bv) :char (bv-char (xor-bv c s))) ; Write a function to decrypt a encrypted message c, using the ; secret s. (defunc decrypt (c s) :input-contract (and (lobvp c) (lobvp s) (equal (len c) (len s))) :output-contract (locharp (decrypt c s)) ...) ; Write a test? to make sure encrypt and decrypt work ; as expected (test? (implies (and (locharp m) (lobvp s) (equal (len m) (len s))) ...)) ; Now, let's see what those secret messages say. ; We're going to turn the list of characters into a string for ; better readability as follows. (coerce (decrypt *code1* *secret1*) 'string) ; The above is an important message. Look up why. (coerce (decrypt *code2* *secret2*) 'string) ; Read this. It provides useful information.