1

I'm trying to translate a C# implementation of the RC4 cipher I wrote to the Racket language.

However, they are producing different keystreams. I have already eliminated the possiblity of miswriting the key-scheduling phase; that must be correct as they result in the same array S. Thus I'm focusing on finding differences in the keystream generation phase.

C#:

public int Dencode (int c)
{
    I = (I + 1) % 256;
    J = (J + S [I]) % 256;
    int tmp = S [I];
    S [I] = S [J];
    S [J] = tmp;
    return S [(S[I] + S[J]) % 256] ^ c;
}

Racket:

(define (toret c)
    (set! i (unsafe-fxmodulo (add1 i) 256))
    (set! j (unsafe-fxmodulo (add1 (Sr i)) 256))
    (swap! (box (Sr i)) (box (Sr j)))
    (bitwise-xor (Sr (unsafe-fxmodulo (+ (Sr i) (Sr j)) 256)) c))

with swap defined as

(define (swap! ba bb)
  (define temp (unbox ba))
  (set-box! ba (unbox bb))
  (set-box! bb temp))

and Sr defined as (define (Sr x) (unsafe-bytes-ref S x)).

What is the difference? Why are these functions producing different output? In both cases i and j are initialized to 0, and S is an identical 256-byte array.

Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
ithisa
  • 752
  • 1
  • 8
  • 25

2 Answers2

1

The line

(swap! (box (Sr i)) (box (Sr j)))

won't do what you expect. It doesn't magically make (Sr i) and (Sr j) mutable references. The swap! procedure swaps the contents of the boxes---but the boxes contain (Sr i) and (Sr j) by value, not by reference.

What you need to do is to amend your swap! procedure to use unsafe-bytes-set! instead.


Here's some code to demonstrate my point:

#lang racket
(require racket/unsafe/ops)

(define (box-swap! x y)
  (define tmp (unbox x))
  (set-box! x (unbox y))
  (set-box! y tmp))

(define (wrong-swap! bs x y)
  (box-swap! (box (unsafe-bytes-ref bs x))
             (box (unsafe-bytes-ref bs y))))

(define (right-swap! bs x y)
  (define tmp (unsafe-bytes-ref bs x))
  (unsafe-bytes-set! bs x (unsafe-bytes-ref bs y))
  (unsafe-bytes-set! bs y tmp))

Example:

> (define bs (bytes 1 2 3 4 5 6))
> bs
#"\1\2\3\4\5\6"
> (wrong-swap! bs 0 5)
> bs
#"\1\2\3\4\5\6"
> (right-swap! bs 0 5)
> bs
#"\6\2\3\4\5\1"
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • It does work per my tests. `S` is a `bytes` type, not a `vector` type. Anyways, I found my error. – ithisa Sep 07 '13 at 17:12
  • @EricDong You've found one error, not the only error. You still need to reformulate your `swap!` to use `unsafe-bytes-set!`; your use of boxes is still incorrect (and turns the `swap!` call into an effective no-op). – C. K. Young Sep 07 '13 at 17:14
  • Make no mistake: all your `S[x] = y;` statements _must_ eventually turn into `unsafe-bytes-set!` calls. Using boxes won't get around that requirement. – C. K. Young Sep 07 '13 at 17:18
-1

There was a very stupid error. (set! j (unsafe-fxmodulo (add1 (Sr i)) 256)) is not equivalent to J = (J + S [I]) % 256;! Adding debug printf lines after each statement helped a lot.

ithisa
  • 752
  • 1
  • 8
  • 25