fork download
  1. ; rc40
  2.  
  3. (define (string-index c str)
  4. (let loop ((ss (string->list str)) (k 0))
  5. (cond ((null? ss) #f)
  6. ((char=? (car ss) c) k)
  7. (else (loop (cdr ss) (+ k 1))))))
  8.  
  9. ; tilde represents shift
  10.  
  11. (define alpha "abcdefghijklmnopqrstuvwxyz0123456789.? ~")
  12. (define shift "ABCDEFGHIJKLMNOPQRSTUVWXYZ)!@#$%^&*(,/|~")
  13.  
  14. (define (c->i c) (string-index c alpha))
  15. (define (i->c i) (string-ref alpha i))
  16.  
  17. ; convert list [~burrito ~~sale~~ 2 ~2 ~47.99] to "Burrito SALE 2 @ $7.99"
  18. (define (rc40->string cs)
  19. (let loop ((cs cs) (locked? #f) (ss (list)))
  20. (cond ((null? cs) (list->string (reverse ss)))
  21. ((and locked? (pair? (cdr cs)) (char=? (car cs) #\~) (char=? (cadr cs) #\~))
  22. (loop (cddr cs) #f ss))
  23. (locked? (loop (cdr cs) #t (cons (string-ref shift (c->i (car cs))) ss)))
  24. ((and (pair? (cdr cs)) (char=? (car cs) #\~) (char=? (cadr cs) #\~))
  25. (loop (cddr cs) #t ss))
  26. ((and (pair? cs) (char=? (car cs) #\~))
  27. (loop (cddr cs) #f (cons (string-ref shift (c->i (cadr cs))) ss)))
  28. (else (loop (cdr cs) #f (cons (car cs) ss))))))
  29.  
  30. ; convert "Burrito SALE 2 @ $7.99" to list [~burrito ~~sale~~ 2 ~2 ~47.99]
  31. (define (string->rc40 str)
  32. (let loop ((cs (string->list str)) (locked? #f) (ss (list)))
  33. (cond ((null? cs)
  34. (if locked?
  35. (reverse (cons #\~ (cons #\~ ss)))
  36. (reverse ss)))
  37. (locked?
  38. (if (string-index (car cs) shift)
  39. (loop (cdr cs) #t
  40. (cons (string-ref alpha (string-index (car cs) shift)) ss))
  41. (loop cs #f (cons #\~ (cons #\~ ss)))))
  42. ((string-index (car cs) shift)
  43. (if (and (pair? (cdr cs)) (string-index (cadr cs) shift))
  44. (loop cs #t (cons #\~ (cons #\~ ss)))
  45. (loop (cdr cs) #f
  46. (cons (string-ref alpha (string-index (car cs) shift))
  47. (cons #\~ ss)))))
  48. (else (loop (cdr cs) #f (cons (car cs) ss))))))
  49.  
  50. (define (rc40-init key)
  51. (let ((kvec (make-vector 40)) (klen (string-length key)) (j 0)
  52. (key (list->string (string->rc40 key))))
  53. (do ((i 0 (+ i 1))) ((= i 40)) (vector-set! kvec i i))
  54. (do ((i 0 (+ i 1))) ((= i 40) kvec)
  55. (set! j (modulo (+ j (vector-ref kvec i)
  56. (c->i (string-ref key (modulo i klen)))) 40))
  57. (let ((t (vector-ref kvec i)))
  58. (vector-set! kvec i (vector-ref kvec j))
  59. (vector-set! kvec j t)))))
  60.  
  61. (define (rc40-stream key)
  62. (let ((i 0) (j 0) (kvec (rc40-init key)))
  63. (lambda ()
  64. (set! i (modulo (+ i 1) 40))
  65. (set! j (modulo (+ j (vector-ref kvec i)) 40))
  66. (let ((t (vector-ref kvec j)))
  67. (vector-set! kvec j (vector-ref kvec i))
  68. (vector-set! kvec i t))
  69. (vector-ref kvec (modulo (+ (vector-ref kvec i) (vector-ref kvec j)) 40)))))
  70.  
  71. (define (rc40-plus a b) (modulo (+ a b) 40))
  72. (define (rc40-minus a b) (modulo (- b a) 40))
  73.  
  74. (define (rc40-encipher key text)
  75. (let ((rc40 (rc40-stream key)))
  76. (let loop ((ts (map c->i (string->rc40 text))) (zs '()))
  77. (if (null? ts) (rc40->string (map i->c (reverse zs)))
  78. (loop (cdr ts) (cons (rc40-plus (rc40) (car ts)) zs))))))
  79.  
  80. (define (rc40-decipher key text)
  81. (let ((rc40 (rc40-stream key)))
  82. (let loop ((ts (map c->i (string->rc40 text))) (zs '()))
  83. (if (null? ts) (rc40->string (map i->c (reverse zs)))
  84. (loop (cdr ts) (cons (rc40-minus (rc40) (car ts)) zs))))))
  85.  
  86. (display (rc40-encipher "tedunangst" "Programming Praxis sharpens your saw.")) (newline)
  87. (display (rc40-decipher "tedunangst" "5cxaxlfrfhy6kh38fbplm0mDko58xs.l9Hkz8")) (newline)
Success #stdin #stdout 0.06s 43624KB
stdin
Standard input is empty
stdout
5cxaxlfrfhy6kh38fbplm0mDko58xs.l9Hkz8
Programming Praxis sharpens your saw.