ISAAC is a cryptographically secure pseudo-random number generator (CSPRNG) and stream cipher. It was developed by Bob Jenkins from 1993 (http://burtleburtle.net/bob/rand/isaac.html) and placed in the Public Domain. ISAAC is fast - especially when optimised - and portable to most architectures in nearly all programming and scripting languages.
It is also simple and succinct, using as it does just two 256-word arrays for its state.

ISAAC stands for "Indirection, Shift, Accumulate, Add, and Count" which are the principal bitwise operations employed.
To date - and that's after more than 20 years of existence - ISAAC has not been broken (unless GCHQ or NSA did it, but they wouldn't be telling).
ISAAC thus deserves a lot more attention than it has hitherto received and it would be salutary to see it more universally implemented.



Task

Translate ISAAC's reference C or Pascal code into your language of choice.

The RNG should then be seeded with the string "this is my secret key" and
finally the message "a Top Secret secret" should be encrypted on that key.
Your program's output cipher-text will be a string of hexadecimal digits.

Optional: Include a decryption check by re-initializing ISAAC and performing
the same encryption pass on the cipher-text.

Please use the C or Pascal as a reference guide to these operations.

Two encryption schemes are possible:
(1) XOR (Vernam) or
(2) Caesar-shift mod 95 (Vigenère).
XOR is the simplest; C-shifting offers greater security.

You may choose either scheme, or both, but please specify which you used.
Here are the alternative sample outputs for checking purposes:

Message: a Top Secret secret
Key    : this is my secret key
XOR    : 1C0636190B1260233B35125F1E1D0E2F4C5422
MOD    : 734270227D36772A783B4F2A5F206266236978
XOR dcr: a Top Secret secret
MOD dcr: a Top Secret secret

No official seeding method for ISAAC has been published, but for this task
we may as well just inject the bytes of our key into the randrsl array,
padding with zeroes before mixing, like so:

// zeroise mm array
FOR i:= 0 TO 255 DO mm[i]:=0;
// check seed's highest array element
m := High(seed);
// inject the seed
FOR i:= 0 TO 255 DO BEGIN
	// in case seed[] has less than 256 elements.
	IF i>m THEN randrsl[i]:=0  
		ELSE randrsl[i]:=seed[i];
END;
// initialize ISAAC with seed
RandInit(true);

ISAAC can of course also be initialized with a single 32-bit unsigned integer in the manner of traditional RNGs, and indeed used as such for research and gaming purposes.
But building a strong and simple ISAAC-based stream cipher - replacing the irreparably broken RC4 - is our goal here: ISAAC's intended purpose.




' version 03-11-2016
' compile with: fbc -s console
 
Dim Shared As UInteger<32> randrsl(256), randcnt
Static Shared As UInteger<32> mm(256)
Static Shared As UInteger<32> aa, bb ,cc
 
Sub ISAAC()
 
    Dim As UInteger<32> i, x, y
 
    cc = cc + 1
    bb = bb + cc
 
    For i = 0 To 256 -1
        x = mm(i)
        Select Case (i Mod 4)
            Case 0 : aa = aa Xor (aa Shl 13)
            Case 1 : aa = aa Xor (aa Shr 6)
            Case 2 : aa = aa Xor (aa Shl 2)
            Case 3 : aa = aa Xor (aa Shr 16)
        End Select
        aa = mm((i+128) Mod 256) + aa
        y = mm((x Shr 2) Mod 256) + aa + bb : mm(i) = y
        bb = mm((y Shr 10) Mod 256) + x : randrsl(i) = bb
    Next
 
    randcnt = 0
 
End Sub
 
 
#Macro mix(a, b, c, d, e, f, g, h)
 
    a Xor= b Shl 11 : d += a : b += c
    b Xor= c Shr 2  : e += b : c += d
    c Xor= d Shl 8  : f += c : d += e
    d Xor= e Shr 16 : g += d : e += f
    e Xor= f Shl 10 : h += e : f += g
    f Xor= g Shr 4  : a += f : g += h
    g Xor= h Shl 8  : b += g : h += a
    h Xor= a Shr 9  : c += h : a += b
 
#EndMacro
 
Sub randinit(flag As Long)
 
    Dim As Long i
    Dim As UInteger<32> a = &H9e3779b9   '/* the golden ratio *
    Dim As UInteger<32> b = &H9e3779b9
    Dim As UInteger<32> c = &H9e3779b9
    Dim As UInteger<32> d = &H9e3779b9
    Dim As UInteger<32> e = &H9e3779b9
    Dim As UInteger<32> f = &H9e3779b9
    Dim As UInteger<32> g = &H9e3779b9
    Dim As UInteger<32> h = &H9e3779b9
    aa = 0 : bb = 0 : cc = 0
 
    For i = 0 To 3
        mix(a, b, c, d, e, f, g, h)
    Next
 
    For i = 0 To 255 Step 8
        If flag = 1 Then
            a += randrsl(i   ) : b += randrsl(i +1)
            c += randrsl(i +2) : d += randrsl(i +3)
            e += randrsl(i +4) : f += randrsl(i +5)
            g += randrsl(i +6) : h += randrsl(i +7)
 
            mix(a, b, c, d, e, f, g, h)
            mm(i   ) = a : mm(i +1) = b : mm(i +2) = c : mm(i +3) = d
            mm(i +4) = e : mm(i +5) = f : mm(i +6) = g : mm(i +7) = h
        End If
    Next
 
    If flag = 1 Then
        For i = 0 To 255 Step 8
            a += mm(i   ) : b += mm(i +1)
            c += mm(i +2) : d += mm(i +3)
            e += mm(i +4) : f += mm(i +5)
            g += mm(i +6) : h += mm(i +7)
 
            mix(a, b, c, d, e, f, g, h)
            mm(i   )= a : mm(i +1) = b : mm(i +2) = c : mm(i +3) = d
            mm(i +4)= e : mm(i +5) = f : mm(i +6) = g : mm(i +7) = h
        Next
    End If
 
    ISAAC()
    randcnt = 0
 
End Sub
 
' // Get a random 32-bit value 0..MAXINT
Function iRandom() As UInteger<32>
 
Dim As UInteger<32> r = randrsl(randcnt)
randcnt += 1
If randcnt > 255 Then
    ISAAC()
    randcnt = 0
End If
 
Return r
 
End Function
 
' // Get a random character in printable ASCII range
Function iRandA() As UByte
 
Return iRandom() Mod 95 +32
 
End Function
 
' // Seed ISAAC with a string
Sub iSeed(seed As String, flag As Long)
 
Dim As ULong i, m = Len(seed) -1
 
For i = 0 To 255
    mm(i) = 0
Next
 
For i = 0 To 255
 
    If i > m Then
        randrsl(i) = 0
    Else
        randrsl(i) = seed[i]
    End If
 
Next
 
randinit(flag)
 
End Sub
 
' // maximum length of message
'#define MAXMSG 4096
#Define _MOD_ 95      ' mod is FreeBASIC keyword
#Define _START_ 32    ' start is used as variable name
 
' // cipher modes for Caesar
Enum ciphermode
    mEncipher
    mDecipher
    mNone
End Enum
 
' // XOR cipher on random stream. Output: ASCII string
' no maximum lenght for input and output string
Function Vernam(msg As String) As String
 
Dim As ULong i
Dim As String v
 
For i = 0 To Len(msg) -1
    v += Chr(iRandA() Xor msg[i])
Next
 
Return v
 
End Function
 
' // Caesar-shift a printable character
Function Ceasar(m As ciphermode, ch As UByte, shift As UByte, modulo As UByte, _
                                                     start As UByte) As UByte
 
' FreeBASIC Mod does not handle negative numbers correctly
' also there is litte problem with shift (declared UByte)
' the IIF() statement helps with shift
' to avoid a negative n a 8 times modulo is added
' modulo * 8 get translateted by FreeBASIC to modulo shl 3
Dim As Long n = (ch - start) + IIf(m = mDecipher, -shift, shift) + modulo * 8
n = n Mod modulo
Return start + n
 
End Function
 
' // Caesar-shift a string on a pseudo-random stream
Function CeasarStr(m As ciphermode, msg As String, modulo As UByte, _
                                                    start As UByte) As String
 
Dim As Long i
Dim As String v
 
For i = 0 To Len(msg) -1
    v += Chr(Ceasar(m, msg[i], iRandA(), modulo, start))
Next
 
Return v
 
End Function
 
' ------=< MAIN >=------
 
Dim As Long n, l
Dim As String msg = "a Top Secret secret"
Dim As String key = "this is my secret key"
 
Dim As String vctx, vptx
Dim As String cctx, cptx
 
l = Len(msg)
' // Encrypt: Vernam XOR
iSeed(key, 1)
vctx = Vernam(msg)
' // Encrypt: Caesar
cctx = CeasarStr(mEncipher, msg, _mod_, _start_)
' // Decrypt: Vernam XOR
iSeed(key, 1)
vptx = Vernam(vctx)
' // Decrypt: Caesar
cptx = CeasarStr(mDecipher, cctx, _mod_, _start_)
Print "message: "; msg
Print "    key: "; key
Print "    XOR: ";
' // Output Vernam ciphertext as a string of hex digits
For n = 0 To l -1
    Print Hex(vctx[n], 2);
Next
Print
' // Output Vernam decrypted plaintext
Print "XOR dcr: "; vptx
' // Caesar
Print "    MOD: ";
' // Output Caesar ciphertext as a string of hex digits
For n= 0 To l -1
    Print Hex(cctx[n], 2);
Next
Print
' // Output Caesar decrypted plaintext
Print "MOD dcr: " ; cptx
 
' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End