ARC4 en Lisp

Últimamente he estado trasteando con Common Lisp, y ya que tengo la constumbre de escribir una implementación de ARC4 como prueba de un lenguaje, ahí va una (está comentada de más precisamente para servir como ejemplo):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
;; Es el paquete ARC4.
(defpackage :arc4)

;; Macro que intercambia dos variables.
(defmacro swap(x y)
  "Intercambia los valores de X e Y"
  (let ((tmp (gensym)))   ; Genera un símbolo para guardar el valor temporal.
    `(let ((,tmp ,x))     ; Guarda el valor temporal de X.
       (setf ,x ,y)       ; Asigna a X el valor de Y.
       (setf ,y ,tmp))))  ; Asigna a Y el valor guardado en el símbolo temporal.


;; Genera un rango al estilo de python.
(defun range(top)
  "Genera una lista de (0 1 .. top - 1)"
  (let ((rng '() ))                        ; Inicializa una lista vacía.
    (loop for i from (- top 1) downto 0 do ; Va descendiendo desde el valor indicado.
     (push i rng))                     ; Y lo introduce de primero en la lista.
    rng))                                  ; Por último devolvemos la lista.


;; Key Scheduling Algorithm.
(defun ksa (key)
  "Inicializa el array de estado"
  (let ((S (range 256))            ; Se inicializa S como una lista de 0 a 255 .
    (j 0)                      ; j se inicializa a 0 .
    (key-length (length key))) ; La longitud de la clave.

  (loop for i from 0 to 255 do   ; De i desde 0 a 255 (ambos incluidos).
       (setf j (mod (+ j         ; j = j + S[i] + k[i % len(k)]
               (nth i S) 
               (char-code (char key (mod i key-length))))
                256))

       (swap (nth i S) (nth j S))) ; Intercambia S[i] y S[j]

  S))  ; Devuelve S


;; Pseudo Random Generation Algorithm.
(defun cipher(S msg)
  "Cifra el mensaje `msg` a partir del estado S"
  (let ((i 0) (j 0) (code '())) ; Inicializa i y j a 0; y `code` como lista vacía.

(loop for c across msg do               ; Iterando sobre todas las letras del mensaje.
     (setf i (mod (+ i 1) 256))         ; i = (i + 1) % 256 .
     (setf j (mod (+ j (nth i S)) 256)) ; j = (j + S[i]) % 256 .
     (swap (nth i S) (nth j S))         ; Intercambia S[i] y S[j] .

 (let ((k (nth (mod (+ (nth i S)    ; k = S[(S[i] + S[j]) % 256] .
                   (nth j S)) 
                256)
               S)))

       (setf code (append code (list (logxor ; Añade a la lista `code` c XOR k .
                      (char-code c)
                      k))))))
    code)) ; Devuelve la lista `code`.


;; Envoltorio
(defun arc4(msg key)
  "Cifra con ARC4 el mensaje `msg` con la clave `key`"
  (let ((S (ksa key))) ; KSA
    (cipher S msg)))   ; PRNG


; Ejemplo
(format t "~a~%" (arc4 "pedia" "Wiki"))

Recursos útiles:
r/lisp
Practical Common Lisp

Eliminar el 'Compressed Header' de los vídeos MKV [tip] » « Llevando la contraria sobre la sintaxis de arrays en C