Vigenère cipher: Difference between revisions

Content added Content deleted
(→‎{{header|TXR}}: Much shorter Lisp code is now possible.)
Line 2,644: Line 2,644:
<lang txr>@(next :args)
<lang txr>@(next :args)
@(do
@(do
(defun vig-op (plus-or-minus)
(defun letter-mod26-op (func) ;; add or subtract capital letters modulo 26
(lambda (a b) (+ #\A (mod (call func (- a #\A) (- b #\A)) 26))))
(op + #\A [mod [plus-or-minus (- @1 #\A) (- @2 #\A)] 26]))

(defun vig (msg key encrypt)
(defun vig (msg key encrypt)
(cat-str (mapcar (letter-mod26-op (if encrypt (fun +) (fun -)))
(mapcar (vig-op [if encrypt + -]) msg (repeat key))))
(list-str msg)
(repeat (list-str key))) "")))
@(coll)@{key /[A-Za-z]/}@(end)
@(coll)@{key /[A-Za-z]/}@(end)
@(coll)@{msg /[A-Za-z]/}@(end)
@(coll)@{msg /[A-Za-z]/}@(end)
Line 2,669: Line 2,668:
Here, the TXR pattern language is used to scan letters out of two arguments, and convert them to upper case. The embedded TXR Lisp dialect handles the Vigenère logic, in just a few lines of code.
Here, the TXR pattern language is used to scan letters out of two arguments, and convert them to upper case. The embedded TXR Lisp dialect handles the Vigenère logic, in just a few lines of code.


Lisp programmers may do a "double take" at what is going on here: yes <code>mapcar</code> can operate on strings and return strings in TXR Lisp. <code>(repeat key)</code> produces an infinite lazy list; but that's okay because <code>mapcar</code> stops after the shortest input runs out of items.
The Vigenère substitution is driven by good old Lisp <code>mapcar</code> which works over the data represented as lists of characters (provided by applying the <code>list-str</code> function to the string inputs).

Now <code>mapcar</code> walks lists in parallel, stopping at the end of the shortest list. This traditional behavior of <code>mapcar</code> turns out to be a very good idea when you introduce infinite lazy lists into the mix. Infinite lists are longer than concrete lists and so mapcar keeps going until the shortest concrete list runs out.

We can represent the text to be enciphered or deciphered as a concrete list of the letters, and the Vigenère key as an infinite lazy list, giving us a key pad which consists of an infinite number of repetitions of the key. Such a list is produced by TXR Lisp's <code>repeat</code> operator, which takes a list and makes a lazy list out of repetitions of that list.

Then <code>mapcar</code> will zip the text and the infinite key pad two together, through the addition or subtraction operation.


Run:
TXR Lisp's <code>+</code> and <code>-</code> operators are generic over characters. An integer may be added to a character to produce a displacement through the code space to get to another character. When a character is subtracted from another, the result is an integer which is the difference between their codes.


<pre>$ ./txr vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!'
<pre>$ txr vigenere.txr 'vigenere cipher' 'Beware the Jabberwock... The jaws that... the claws that catch!'
text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
text: BEWARETHEJABBERWOCKTHEJAWSTHATTHECLAWSTHATCATCH
key: VIGENERECIPHER
key: VIGENERECIPHER