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