Task: The ISAAC cipher


C++: #include <iomanip>
#include <iostream> 
#include <sstream>
using namespace std;

enum CipherMode {ENCRYPT, DECRYPT};


uint32_t randRsl[256];
uint32_t randCnt;


uint32_t mm[256]; 
uint32_t aa = 0, bb = 0, cc = 0;

void isaac()
{   
    ++cc;  
    bb += cc; 
   
    for (uint32_t i = 0; i < 256; ++i)
    {
        uint32_t x, y;

        x = mm[i];
        switch (i % 4)
        {
            case 0: 
                aa = aa ^ (aa << 13); 
                break;
            case 1:
                aa = aa ^ (aa >> 6); 
                break;
            case 2:
                aa = aa ^ (aa << 2);
                break;
            case 3:
                aa = aa ^ (aa >> 16);
                break;
        }
        aa = mm[(i + 128) % 256] + aa;
        y = mm[(x >> 2) % 256] + aa + bb;
        mm[i] = y;
        bb = mm[(y >> 10) % 256] + x;
        randRsl[i] = bb; 
    }
    randCnt = 0; 
}

void mix(uint32_t a[])
{  
    a[0] = a[0] ^ a[1] << 11; a[3] += a[0]; a[1] += a[2];
    a[1] = a[1] ^ a[2] >>  2; a[4] += a[1]; a[2] += a[3];
    a[2] = a[2] ^ a[3] <<  8; a[5] += a[2]; a[3] += a[4];
    a[3] = a[3] ^ a[4] >> 16; a[6] += a[3]; a[4] += a[5];
    a[4] = a[4] ^ a[5] << 10; a[7] += a[4]; a[5] += a[6];
    a[5] = a[5] ^ a[6] >>  4; a[0] += a[5]; a[6] += a[7];
    a[6] = a[6] ^ a[7] <<  8; a[1] += a[6]; a[7] += a[0];
    a[7] = a[7] ^ a[0] >>  9; a[2] += a[7]; a[0] += a[1];  
}

void randInit(bool flag)
{
    uint32_t a[8];
    aa = bb = cc = 0;
   
    a[0] = 2654435769UL; 
    for (uint32_t j = 1; j < 8; ++j)
        a[j] = a[0];
   
    for (uint32_t i = 0; i < 4; ++i) 
        mix(a);
    for (uint32_t i = 0; i < 256; i += 8) 
    {
        if (flag) 
            for (uint32_t j = 0; j < 8; ++j)
                a[j] += randRsl[i + j];
        mix(a);
        for (uint32_t j = 0; j < 8; ++j)
            mm[i + j] = a[j];
    }
   
    if (flag)
    {   
        for (uint32_t i = 0; i < 256; i += 8)
        {
            for (uint32_t j = 0; j < 8; ++j)
                a[j] += mm[i + j];
            mix(a);
            for (uint32_t j = 0; j < 8; ++j)
                mm[i + j] = a[j];
        }
    }   
    isaac(); 
    randCnt = 0; 
}



void seedIsaac(string seed, bool flag)
{
    uint32_t seedLength = seed.length();
    for (uint32_t i = 0; i < 256; i++)
        mm[i] = 0;
    for (uint32_t i = 0; i < 256; i++)
        
        randRsl[i] = i > seedLength ? 0 : seed[i];
    
    randInit(flag);
}


uint32_t getRandom32Bit()
{
    uint32_t result = randRsl[randCnt];
    ++randCnt;
    if (randCnt > 255)
    {
        isaac();
        randCnt = 0;
    }
    return result;
}


char getRandomChar()
{       
    return getRandom32Bit() % 95 + 32;
}


string ascii2hex(string source)
{
    uint32_t sourceLength = source.length();
    stringstream ss;
    for (uint32_t i = 0; i < sourceLength; i++) 
        ss << setfill ('0') << setw(2) << hex << (int) source[i];
    return ss.str(); 
}


string vernam(string msg)
{
    uint32_t msgLength = msg.length();
    string destination = msg;
    for (uint32_t i = 0; i < msgLength; i++) 
        destination[i] = getRandomChar() ^ msg[i];
    return destination;    
}
        

char caesar(CipherMode m, char ch, char shift, char modulo, char start)
{
    int n;
    if (m == DECRYPT)
        shift = -shift;
    n = (ch - start) + shift;
    n %= modulo;
    if (n < 0) 
        n += modulo;
    return start + n;
}
        

string vigenere(string msg, CipherMode m)
{
    uint32_t msgLength = msg.length();
    string destination = msg;
    
    for (uint32_t i = 0; i < msgLength; ++i) 
        destination[i] = caesar(m, msg[i], getRandomChar(), 95, ' ');
    return destination; 
}
        
int main()
{
    
    string msg = "a Top Secret secret";
    string key = "this is my secret key";
    string xorCipherText, modCipherText, xorPlainText, modPlainText;
    
    
    seedIsaac(key, true);
    
    
    xorCipherText = vernam(msg);
    
    modCipherText = vigenere(msg, ENCRYPT);
    
    seedIsaac(key, true);
    
    xorPlainText = vernam(xorCipherText);
    
    modPlainText = vigenere(modCipherText, DECRYPT);
    
    cout << "Message: " << msg << endl;
    cout << "Key    : " << key << endl;
    cout << "XOR    : " << ascii2hex(xorCipherText) << endl;
    cout << "MOD    : " << ascii2hex(modCipherText) << endl;
    cout << "XOR dcr: " << xorPlainText << endl;
    cout << "MOD dcr: " << modPlainText << endl;
}



Go: package main

import "fmt"

const (
    msg = "a Top Secret secret"
    key = "this is my secret key"
)

func main() {
    var z state
    z.seed(key)
    fmt.Println("Message: ", msg)
    fmt.Println("Key    : ", key)
    fmt.Println("XOR    : ", z.vernam(msg))
}

type state struct {
    aa, bb, cc uint32
    mm         [256]uint32
    randrsl    [256]uint32
    randcnt    int
}

func (z *state) isaac() {
    z.cc++
    z.bb += z.cc
    for i, x := range z.mm {
        switch i % 4 {
        case 0:
            z.aa = z.aa ^ z.aa<<13
        case 1:
            z.aa = z.aa ^ z.aa>>6
        case 2:
            z.aa = z.aa ^ z.aa<<2
        case 3:
            z.aa = z.aa ^ z.aa>>16
        }
        z.aa += z.mm[(i+128)%256]
        y := z.mm[x>>2%256] + z.aa + z.bb
        z.mm[i] = y
        z.bb = z.mm[y>>10%256] + x
        z.randrsl[i] = z.bb
    }
}

func (z *state) randInit() {
    const gold = uint32(0x9e3779b9)
    a := [8]uint32{gold, gold, gold, gold, gold, gold, gold, gold}
    mix1 := func(i int, v uint32) {
        a[i] ^= v
        a[(i+3)%8] += a[i]
        a[(i+1)%8] += a[(i+2)%8]
    }
    mix := func() {
        mix1(0, a[1]<<11)
        mix1(1, a[2]>>2)
        mix1(2, a[3]<<8)
        mix1(3, a[4]>>16)
        mix1(4, a[5]<<10)
        mix1(5, a[6]>>4)
        mix1(6, a[7]<<8)
        mix1(7, a[0]>>9)
    }
    for i := 0; i < 4; i++ {
        mix()
    }
    for i := 0; i < 256; i += 8 {
        for j, rj := range z.randrsl[i : i+8] {
            a[j] += rj
        }
        mix()
        for j, aj := range a {
            z.mm[i+j] = aj
        }
    }
    for i := 0; i < 256; i += 8 {
        for j, mj := range z.mm[i : i+8] {
            a[j] += mj
        }
        mix()
        for j, aj := range a {
            z.mm[i+j] = aj
        }
    }
    z.isaac()
}

func (z *state) seed(seed string) {
    for i, r := range seed {
        if i == 256 {
            break
        }
        z.randrsl[i] = uint32(r)
    }
    z.randInit()
}

func (z *state) random() (r uint32) {
    r = z.randrsl[z.randcnt]
    z.randcnt++
    if z.randcnt == 256 {
        z.isaac()
        z.randcnt = 0
    }
    return
}

func (z *state) randA() byte {
    return byte(z.random()%95 + 32)
}

func (z *state) vernam(msg string) string {
    b := []byte(msg)
    for i := range b {
        b[i] ^= z.randA()
    }
    return fmt.Sprintf("%X", b)
}