; blum blum shub
(define (digits n . args)
(let ((b (if (null? args) 10 (car args))))
(let loop ((n n) (d '()))
(if (zero? n) d
(loop (quotient n b)
(cons (modulo n b) d))))))
(define (undigits ds . args)
(let ((b (if (null? args) 10 (car args))))
(let loop ((ds ds) (n 0))
(if (null? ds) n
(loop (cdr ds) (+ (* n b) (car ds)))))))
(define (logxor x y)
(let loop ((x (reverse (digits x 2))) (y (reverse (digits y 2))) (z '()))
(cond ((and (null? x) (null? y)) (undigits z 2))
((and (null? x) (zero? (car y))) (loop x (cdr y) (cons 0 z)))
((null? x) (loop x (cdr y) (cons 1 z)))
((and (null? y) (zero? (car x))) (loop (cdr x) y (cons 0 z)))
((null? y) (loop (cdr x) y (cons 1 z)))
((= (car x) (car y)) (loop (cdr x) (cdr y) (cons 0 z)))
(else (loop (cdr x) (cdr y) (cons 1 z))))))
(define (make-blum-blum-shub n s)
(let ((s s))
(lambda ()
(set! s (modulo (* s s) n))
(modulo s 256))))
(define (encipher n s plain-text)
(let ((bbs (make-blum-blum-shub n s)))
(let loop ((ps (string->list plain-text)) (cs '()))
(if (null? ps)
(list->string (reverse cs))
(loop (cdr ps) (cons (integer->char
(logxor (bbs) (char->integer (car ps)))) cs))))))
(define decipher encipher)
(display (decipher 974153 17 (encipher 974153 17 "PROGRAMMING PRAXIS")))
(newline)
(display (map char->integer (string->list (encipher 974153 17 "PROGRAMMING PRAXIS"))))