rendered paste body;; Common Lisp RC4 implementation as an exercise
;; Released in the Public Domain.
;; TODO:
;; - Attempt to specialize methods afterwards for other objects than strings
;; - Attempt to cleanup code further
;; - Write with-key-init or such macro
;; - Write stream-type functions for it
(declaim (optimize (speed 3) (safety 1))
(inline -key-init)
(inline key-random)
(inline key-random-add))
(defpackage :mm-rc4
(:use :cl)
(:nicknames :rc4)
(:export
#:key-init
#:key-random-add
#:key-random
#:key-destroy))
(in-package :rc4)
(defclass rc4-type ()
((x
:type fixnum
:accessor key-x
:initform 0)
(y
:type fixnum
:accessor key-y
:initform 0)
(state
:type (simple-array fixnum (256))
:accessor key-state
:initform (make-array 256 :element-type 'fixnum :initial-element 0))))
(defgeneric -key-init (key))
(defmethod -key-init ((k rc4-type))
(setf (key-x k) 0)
(setf (key-y k) 0)
(loop
for i from 0 to 255
do (setf (aref (the (simple-array fixnum (256)) (key-state k)) i) i)))
(defgeneric key-init (key data discard))
(defmethod key-init ((k rc4-type) (s string) (discard fixnum))
(-key-init k)
(key-random-add k s discard))
(defgeneric key-random-add (key data discard))
(defmethod key-random-add ((k rc4-type) (s string) (discard fixnum))
(let ((y 0) (si 0) (slen (length s)))
(with-accessors ((sa key-state)) k
(declare (type fixnum y si slen)
(type (simple-array fixnum (256)) sa)
(type (simple-array character (*)) s))
(loop
for x from 0 to 255
do (progn
(setf
y (logand (+ y (aref sa x) (char-code (char s si))) #Xff)
si (mod (1+ si) slen))
(psetf (aref sa x) (aref sa y)
(aref sa y) (aref sa x))))))
(loop
repeat discard
do (key-random k)))
(defgeneric key-random (key))
(defmethod key-random ((k rc4-type))
(with-accessors ((sa key-state) (kx key-x) (ky key-y)) k
(declare (type fixnum kx ky)
(type (simple-array fixnum (256)) sa))
(setf
kx (logand (1+ kx) #Xff)
ky (logand (+ ky (aref sa kx)) #Xff))
(psetf (aref sa kx) (aref sa ky)
(aref sa ky) (aref sa kx))
(aref sa (logand (+ (aref sa kx) (aref sa ky)) #Xff))))
(defgeneric key-encode (k s))
;; XXX This would fail with length == 0!
;; Also, now only supports destructive mode.
(defmethod key-encode ((k rc4-type) (s string))
(let ((slen (1- (length s))))
(declare (type fixnum slen)
(type (simple-array character (*)) s))
(loop
for i from 0 to slen
do (setf (char s i)
(code-char
(logxor (char-code (char s i))
(the fixnum (key-random k)))))))
s)
(defgeneric key-destroy (k))
(defmethod key-destroy ((k rc4-type))
(setf (key-x k) 0)
(setf (key-y k) 0)
(loop
for i from (the fixnum 0) to 255
do (setf (aref (the (simple-array fixnum (256)) (key-state k)) i) 0)))
(defvar *k*)
(setf *k* (make-instance 'rc4-type))
(key-init *k* "This is a test" 3072)
;;(key-destroy *k*)