#|
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.


