SHA-3

From CasperTech Wiki
Revision as of 12:28, 27 February 2017 by D1cd5b71-6209-4595-9bf0-771bf689ce00 (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Here's an open source SHA-3 implementation in LSL.

It supports all three versions of the algorithm - SHA-3, Keccak, SHAKE.

Processing speed is roughly 100 characters per second.

/////////////////////////////////////////////////////////////////////////////////
//
//      CasperTech SHA-3 implementation
//
//      Creative Commons Attribution 4.0 International https://creativecommons.org/licenses/by/4.0/
//
//      Based on js-sha3 https://github.com/emn178/js-sha3
//
////////////////////////////////////////////////////////////////////////////////

list HEX_CHARS = ["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"];
list SHAKE_PADDING = [31, 7936, 2031616, 520093696];
list KECCAK_PADDING = [1, 256, 65536, 16777216];
list PADDING = [6, 1536, 393216, 100663296];
list SHIFT = [0, 8, 16, 24];
list RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649,
            0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0,
            2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771,
            2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648,
            2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648];
            
integer ALGORITHM_SHA3 = 0;
integer ALGORITHM_KECCAK = 1;
integer ALGORITHM_SHAKE = 2;

integer UTF8ToUnicodeInteger(string input) //From http://wiki.secondlife.com/w/index.php?title=UTF-8 with thanks
{
    integer result = llBase64ToInteger(llStringToBase64(input = llGetSubString(input,0,0)));
    if(result & 0x80000000)
    {
        integer end = (integer)("0x"+llGetSubString(input = (string)llParseString2List(llEscapeURL(input),(list)"%",[]),-8,-1));
        integer begin = (integer)("0x"+llDeleteSubString(input,-8,-1));
        return  (   (  0x0000003f &  end       ) |
                    (( 0x00003f00 &  end) >> 2 ) | 
                    (( 0x003f0000 &  end) >> 4 ) | 
                    (( 0x3f000000 &  end) >> 6 ) |
                    (( 0x0000003f &  begin) << 24) |
                    (( 0x00000100 &  begin) << 22)
                ) & (0x7FFFFFFF >> (5 * ((integer)(llLog(~result) / 0.69314718055994530941723212145818) - 25)));
    }
    return result >> 24;
}
integer zeroFillRightShift(integer value, integer count) //From http://wiki.secondlife.com/wiki/Right_Shift with thanks
{
    return ((value & 0x7fFFffFF) >> count) - ((value & 0x80000000) >> count);
}
list f(list s) 
{
    integer h;
    integer l;
    integer n;
    integer c0;
    integer c1;
    integer c2;
    integer c3;
    integer c4;
    integer c5;
    integer c6;
    integer c7;
    integer c8;
    integer c9;
    integer b0;
    integer b1;
    integer b2;
    integer b3;
    integer b4;
    integer b5;
    integer b6;
    integer b7;
    integer b8;
    integer b9;
    integer b10;
    integer b11;
    integer b12;
    integer b13;
    integer b14;
    integer b15;
    integer b16;
    integer b17;
    integer b18;
    integer b19;
    integer b20;
    integer b21;
    integer b22;
    integer b23;
    integer b24;
    integer b25;
    integer b26;
    integer b27;
    integer b28;
    integer b29;
    integer b30;
    integer b31;
    integer b32;
    integer b33;
    integer b34;
    integer b35;
    integer b36;
    integer b37;
    integer b38;
    integer b39;
    integer b40;
    integer b41;
    integer b42;
    integer b43;
    integer b44;
    integer b45;
    integer b46;
    integer b47;
    integer b48;
    integer b49;
    
    integer s0 = llList2Integer(s,0);
    integer s1 = llList2Integer(s,1);
    integer s2 = llList2Integer(s,2);
    integer s3 = llList2Integer(s,3);
    integer s4 = llList2Integer(s,4);
    integer s5 = llList2Integer(s,5);
    integer s6 = llList2Integer(s,6);
    integer s7 = llList2Integer(s,7);
    integer s8 = llList2Integer(s,8);
    integer s9 = llList2Integer(s,9);
    integer s10 = llList2Integer(s,10);
    integer s11 = llList2Integer(s,11);
    integer s12 = llList2Integer(s,12);
    integer s13 = llList2Integer(s,13);
    integer s14 = llList2Integer(s,14);
    integer s15 = llList2Integer(s,15);
    integer s16 = llList2Integer(s,16);
    integer s17 = llList2Integer(s,17);
    integer s18 = llList2Integer(s,18);
    integer s19 = llList2Integer(s,19);
    integer s20 = llList2Integer(s,20);
    integer s21 = llList2Integer(s,21);
    integer s22 = llList2Integer(s,22);
    integer s23 = llList2Integer(s,23);
    integer s24 = llList2Integer(s,24);
    integer s25 = llList2Integer(s,25);
    integer s26 = llList2Integer(s,26);
    integer s27 = llList2Integer(s,27);
    integer s28 = llList2Integer(s,28);
    integer s29 = llList2Integer(s,29);
    integer s30 = llList2Integer(s,30);
    integer s31 = llList2Integer(s,31);
    integer s32 = llList2Integer(s,32);
    integer s33 = llList2Integer(s,33);
    integer s34 = llList2Integer(s,34);
    integer s35 = llList2Integer(s,35);
    integer s36 = llList2Integer(s,36);
    integer s37 = llList2Integer(s,37);
    integer s38 = llList2Integer(s,38);
    integer s39 = llList2Integer(s,39);
    integer s40 = llList2Integer(s,40);
    integer s41 = llList2Integer(s,41);
    integer s42 = llList2Integer(s,42);
    integer s43 = llList2Integer(s,43);
    integer s44 = llList2Integer(s,44);
    integer s45 = llList2Integer(s,45);
    integer s46 = llList2Integer(s,46);
    integer s47 = llList2Integer(s,47);
    integer s48 = llList2Integer(s,48);
    integer s49 = llList2Integer(s,49);
    
        
        
    for (n = 0; n < 48; n += 2) 
    {
        c0 = s0 ^ s10 ^ s20 ^ s30 ^ s40;
        c1 = s1 ^ s11 ^ s21 ^ s31 ^ s41;
        c2 = s2 ^ s12 ^ s22 ^ s32 ^ s42;
        c3 = s3 ^ s13 ^ s23 ^ s33 ^ s43;
        c4 = s4 ^ s14 ^ s24 ^ s34 ^ s44;
        c5 = s5 ^ s15 ^ s25 ^ s35 ^ s45;
        c6 = s6 ^ s16 ^ s26 ^ s36 ^ s46;
        c7 = s7 ^ s17 ^ s27 ^ s37 ^ s47;
        c8 = s8 ^ s18 ^ s28 ^ s38 ^ s48;
        c9 = s9 ^ s19 ^ s29 ^ s39 ^ s49;
        
        h = c8 ^ ((c2 << 1) | (zeroFillRightShift(c3,31)));
        l = c9 ^ ((c3 << 1) | (zeroFillRightShift(c2,31)));
        s0 = s0 ^ h;
        s1 = s1 ^ l;
        s10 = s10 ^ h;
        s11 = s11 ^ l;
        s20 = s20 ^ h;
        s21 = s21 ^ l;
        s30 = s30 ^ h;
        s31 = s31 ^ l;
        s40 = s40 ^ h;
        s41 = s41 ^ l;
        h = c0 ^ ((c4 << 1) | (zeroFillRightShift(c5,31)));
        l = c1 ^ ((c5 << 1) | (zeroFillRightShift(c4,31)));
        s2 = s2 ^ h;
        s3 = s3 ^ l;
        s12 = s12 ^ h;
        s13 = s13 ^ l;
        s22 = s22 ^ h;
        s23 = s23 ^ l;
        s32 = s32 ^ h;
        s33 = s33 ^ l;
        s42 = s42 ^ h;
        s43 = s43 ^ l;
        h = c2 ^ ((c6 << 1) | (zeroFillRightShift(c7,31)));
        l = c3 ^ ((c7 << 1) | (zeroFillRightShift(c6,31)));
        s4 = s4 ^ h;
        s5 = s5 ^ l;
        s14 = s14 ^ h;
        s15 = s15 ^ l;
        s24 = s24 ^ h;
        s25 = s25 ^ l;
        s34 = s34 ^ h;
        s35 = s35 ^ l;
        s44 = s44 ^ h;
        s45 = s45 ^ l;
        h = c4 ^ ((c8 << 1) | (zeroFillRightShift(c9,31)));
        l = c5 ^ ((c9 << 1) | (zeroFillRightShift(c8,31)));
        s6 = s6 ^ h;
        s7 = s7 ^ l;
        s16 = s16 ^ h;
        s17 = s17 ^ l;
        s26 = s26 ^ h;
        s27 = s27 ^ l;
        s36 = s36 ^ h;
        s37 = s37 ^ l;
        s46 = s46 ^ h;
        s47 = s47 ^ l;
        h = c6 ^ ((c0 << 1) | (zeroFillRightShift(c1,31)));
        l = c7 ^ ((c1 << 1) | (zeroFillRightShift(c0,31)));
        s8 = s8 ^ h;
        s9 = s9 ^ l;
        s18 = s18 ^ h;
        s19 = s19 ^ l;
        s28 = s28 ^ h;
        s29 = s29 ^ l;
        s38 = s38 ^ h;
        s39 = s39 ^ l;
        s48 = s48 ^ h;
        s49 = s49 ^ l;
        
        b0 = s0;
        b1 = s1;
        b32 = (s11 << 4) | (zeroFillRightShift(s10,28));
        b33 = (s10 << 4) | (zeroFillRightShift(s11,28));
        b14 = (s20 << 3) | (zeroFillRightShift(s21,29));
        b15 = (s21 << 3) | (zeroFillRightShift(s20,29));
        b46 = (s31 << 9) | (zeroFillRightShift(s30,23));
        b47 = (s30 << 9) | (zeroFillRightShift(s31,23));
        b28 = (s40 << 18) | (zeroFillRightShift(s41,14));
        b29 = (s41 << 18) | (zeroFillRightShift(s40,14));
        b20 = (s2 << 1) | (zeroFillRightShift(s3,31));
        b21 = (s3 << 1) | (zeroFillRightShift(s2,31));
        b2 = (s13 << 12) | (zeroFillRightShift(s12,20));
        b3 = (s12 << 12) | (zeroFillRightShift(s13,20));
        b34 = (s22 << 10) | (zeroFillRightShift(s23,22));
        b35 = (s23 << 10) | (zeroFillRightShift(s22,22));
        b16 = (s33 << 13) | (zeroFillRightShift(s32,19));
        b17 = (s32 << 13) | (zeroFillRightShift(s33,19));
        b48 = (s42 << 2) | (zeroFillRightShift(s43,30));
        b49 = (s43 << 2) | (zeroFillRightShift(s42,30));
        b40 = (s5 << 30) | (zeroFillRightShift(s4,2));
        b41 = (s4 << 30) | (zeroFillRightShift(s5,2));
        b22 = (s14 << 6) | (zeroFillRightShift(s15,26));
        b23 = (s15 << 6) | (zeroFillRightShift(s14,26));
        b4 = (s25 << 11) | (zeroFillRightShift(s24,21));
        b5 = (s24 << 11) | (zeroFillRightShift(s25,21));
        b36 = (s34 << 15) | (zeroFillRightShift(s35,17));
        b37 = (s35 << 15) | (zeroFillRightShift(s34,17));
        b18 = (s45 << 29) | (zeroFillRightShift(s44,3));
        b19 = (s44 << 29) | (zeroFillRightShift(s45,3));
        b10 = (s6 << 28) | (zeroFillRightShift(s7,4));
        b11 = (s7 << 28) | (zeroFillRightShift(s6,4));
        b42 = (s17 << 23) | (zeroFillRightShift(s16,9));
        b43 = (s16 << 23) | (zeroFillRightShift(s17,9));
        b24 = (s26 << 25) | (zeroFillRightShift(s27,7));
        b25 = (s27 << 25) | (zeroFillRightShift(s26,7));
        b6 = (s36 << 21) | (zeroFillRightShift(s37,11));
        b7 = (s37 << 21) | (zeroFillRightShift(s36,11));
        b38 = (s47 << 24) | (zeroFillRightShift(s46,8));
        b39 = (s46 << 24) | (zeroFillRightShift(s47,8));
        b30 = (s8 << 27) | (zeroFillRightShift(s9,5));
        b31 = (s9 << 27) | (zeroFillRightShift(s8,5));
        b12 = (s18 << 20) | (zeroFillRightShift(s19,12));
        b13 = (s19 << 20) | (zeroFillRightShift(s18,12));
        b44 = (s29 << 7) | (zeroFillRightShift(s28,25));
        b45 = (s28 << 7) | (zeroFillRightShift(s29,25));
        b26 = (s38 << 8) | (zeroFillRightShift(s39,24));
        b27 = (s39 << 8) | (zeroFillRightShift(s38,24));
        b8 = (s48 << 14) | (zeroFillRightShift(s49,18));
        b9 = (s49 << 14) | (zeroFillRightShift(s48,18));
        
        s0 = b0 ^ (~b2 & b4);
        s1 = b1 ^ (~b3 & b5);
        s10 = b10 ^ (~b12 & b14);
        s11 = b11 ^ (~b13 & b15);
        s20 = b20 ^ (~b22 & b24);
        s21 = b21 ^ (~b23 & b25);
        s30 = b30 ^ (~b32 & b34);
        s31 = b31 ^ (~b33 & b35);
        s40 = b40 ^ (~b42 & b44);
        s41 = b41 ^ (~b43 & b45);
        s2 = b2 ^ (~b4 & b6);
        s3 = b3 ^ (~b5 & b7);
        s12 = b12 ^ (~b14 & b16);
        s13 = b13 ^ (~b15 & b17);
        s22 = b22 ^ (~b24 & b26);
        s23 = b23 ^ (~b25 & b27);
        s32 = b32 ^ (~b34 & b36);
        s33 = b33 ^ (~b35 & b37);
        s42 = b42 ^ (~b44 & b46);
        s43 = b43 ^ (~b45 & b47);
        s4 = b4 ^ (~b6 & b8);
        s5 = b5 ^ (~b7 & b9);
        s14 = b14 ^ (~b16 & b18);
        s15 = b15 ^ (~b17 & b19);
        s24 = b24 ^ (~b26 & b28);
        s25 = b25 ^ (~b27 & b29);
        s34 = b34 ^ (~b36 & b38);
        s35 = b35 ^ (~b37 & b39);
        s44 = b44 ^ (~b46 & b48);
        s45 = b45 ^ (~b47 & b49);
        s6 = b6 ^ (~b8 & b0);
        s7 = b7 ^ (~b9 & b1);
        s16 = b16 ^ (~b18 & b10);
        s17 = b17 ^ (~b19 & b11);
        s26 = b26 ^ (~b28 & b20);
        s27 = b27 ^ (~b29 & b21);
        s36 = b36 ^ (~b38 & b30);
        s37 = b37 ^ (~b39 & b31);
        s46 = b46 ^ (~b48 & b40);
        s47 = b47 ^ (~b49 & b41);
        s8 = b8 ^ (~b0 & b2);
        s9 = b9 ^ (~b1 & b3);
        s18 = b18 ^ (~b10 & b12);
        s19 = b19 ^ (~b11 & b13);
        s28 = b28 ^ (~b20 & b22);
        s29 = b29 ^ (~b21 & b23);
        s38 = b38 ^ (~b30 & b32);
        s39 = b39 ^ (~b31 & b33);
        s48 = b48 ^ (~b40 & b42);
        s49 = b49 ^ (~b41 & b43);
        
        s0 = s0 ^ llList2Integer(RC, n);
        s1 = s1 ^ llList2Integer(RC, n + 1);
    }
    return [s0,s1,s2,s3,s4,s5,s6,s7,s8,s9,s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s20,s21,s22,s23,s24,s25,s26,s27,s28,s29,s30,s31,s32,s33,s34,s35,s36,s37,s38,s39,s40,s41,s42,s43,s44,s45,s46,s47,s48,s49];  
}
string Keccak(integer bits, list padding, integer outputBits, string message)
{
    list blocks = [];
    list s = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
    integer block = 0;
    integer start = 0;
    integer blockCount = (1600 - (bits << 1)) >> 5;
    
    integer byteCount = blockCount << 2;
    integer outputBlocks = outputBits >> 5;   
    integer extraBytes = (outputBits & 31) >> 3;
    integer length = llStringLength(message);
    integer index = 0;
    integer i;
    integer code;
    integer reset = FALSE;
    integer lastByteIndex = 0;
    
    blocks = [0];
    for(i = 0; i < blockCount + 1; ++i) 
    {
        blocks+=[0];
    }
    
    
    while(index < length)
    {
        if (reset == TRUE)
        {
            reset = FALSE;
            blocks = [block];
            for(i = 0; i < blockCount + 1; ++i) 
            {
                blocks+=[0];
            }
        }
        for(i = start; index < length && i < byteCount; ++index)
        {
            code = UTF8ToUnicodeInteger(llGetSubString(message, index, index));
            integer blockNumber = llList2Integer(blocks, i >> 2);            
            if (code < 0x80)
            {
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | code << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
            } 
            else if (code < 0x800) 
            {
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) |(0xc0 | (code >> 6)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | (code & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
            } 
            else if (code < 0xd800 || code >= 0xe000) 
            {
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0xe0 | (code >> 12)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | ((code >> 6) & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | (code & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
            }
            else 
            {
                index = index + 1;
                code = 0x10000 + (((code & 0x3ff) << 10) | (UTF8ToUnicodeInteger(llGetSubString(message, index, index)) & 0x3ff));
                
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0xf0 | (code >> 18)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | ((code >> 12) & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | ((code >> 6) & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
                blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | (0x80 | (code & 0x3f)) << llList2Integer(SHIFT,i & 3)], i >> 2, i >> 2);
                i = i + 1;
            }
        }
        lastByteIndex = i;
        if (i >= byteCount) 
        {
            start = i - byteCount;
            block = llList2Integer(blocks,blockCount);
            for(i = 0; i < blockCount; ++i)
            {
                s = llListReplaceList(s, [llList2Integer(s,i) ^ llList2Integer(blocks,i)], i, i);    
            }
            s = f(s);
            reset = TRUE;
        }
        else
        {
            start = i;    
        }
    }
    
    //Finalise
    i = lastByteIndex;
    blocks = llListReplaceList(blocks, [llList2Integer(blocks, i >> 2) | llList2Integer(padding, i & 3)],i >> 2, i >> 2);
    if (lastByteIndex == byteCount) 
    {
        blocks = llListReplaceList(blocks, [llList2Integer(blocks, blockCount)], 0, 0);
        for (i = 1; i < blockCount + 1; ++i) 
        {
            blocks = llListReplaceList(blocks, [0], i, i);
        }
    }
    blocks = llListReplaceList(blocks, [llList2Integer(blocks, blockCount - 1) | 0x80000000], blockCount - 1, blockCount - 1);
    
    for (i = 0; i < blockCount; ++i) 
    {
        s = llListReplaceList(s, [llList2Integer(s, i) ^ llList2Integer(blocks,i)], i, i);
    }    

    s = f(s);
    
    //Dump to hex
    integer j = 0;
    string hex = "";
    
    while (j < outputBlocks) 
    {
        for (i = 0; i < blockCount && j < outputBlocks; ++i, ++j) 
        {
            block = llList2Integer(s,i);        
            hex += llList2String(HEX_CHARS,(block >> 4) & 0x0F) + llList2String(HEX_CHARS, block & 0x0F);
            hex += llList2String(HEX_CHARS,(block >> 12) & 0x0F) + llList2String(HEX_CHARS,(block >> 8) & 0x0F);
            hex += llList2String(HEX_CHARS,(block >> 20) & 0x0F) + llList2String(HEX_CHARS,(block >> 16) & 0x0F);
            hex += llList2String(HEX_CHARS,(block >> 28) & 0x0F) + llList2String(HEX_CHARS,(block >> 24) & 0x0F);
        }
        if (j % blockCount == 0) 
        {
            s =f(s);
            i = 0;
        }
    }
    if (extraBytes) 
    {
        block = llList2Integer(s,i);
        if (extraBytes > 0) 
        {
            hex += llList2String(HEX_CHARS,(block >> 4) & 0x0F) + llList2String(HEX_CHARS,block & 0x0F);
        }
        if (extraBytes > 1) 
        {
            hex += llList2String(HEX_CHARS,(block >> 12) & 0x0F) + llList2String(HEX_CHARS,(block >> 8) & 0x0F);
        }
        if (extraBytes > 2) 
        {
            hex += llList2String(HEX_CHARS,(block >> 20) & 0x0F) + llList2String(HEX_CHARS,(block >> 16) & 0x0F);
        }
    }
    return hex;
}

string digest(integer algorithm, integer strength, integer outputBits, string message)
{
    if (algorithm==ALGORITHM_SHA3)
    {
        if (strength==224 || strength == 256 || strength == 384 || strength == 512)
        {
            return Keccak(strength, PADDING, strength, message);   
        }
    }
    else if (algorithm==ALGORITHM_KECCAK)
    {
        if (strength==224 || strength==256 || strength==384 || strength==512 || strength==576)
        {
            return Keccak(strength, KECCAK_PADDING, strength, message);
        }    
    }
    else if (algorithm==ALGORITHM_SHAKE)
    {
        if (strength==128 || strength==256)
        {
            return Keccak(strength, SHAKE_PADDING, outputBits, message);
        }     
    }
    else
    {
        return "ERROR: Invalid algorithm";   
    }
    return "ERROR: Invalid parameters for algorithm";
}
integer total = 0;
integer passed = 0;
doTest(string testName, integer algorithm, integer bits, integer outputBits, string message, string expected)
{
    llResetTime();
     llSetText("Running "+testName,<1.0,1.0,1.0>,1.0);
    string result = digest(algorithm, bits, outputBits, message);
    string conclusion = "FAILED";
    total++;
    if (result == expected)
    {
        passed++;
        //Don't output passes
        conclusion = "PASSED in "+(string)llGetTime()+" seconds";
    }
    else
    {
        conclusion+=" Got: "+result+", Expected: "+expected;    
    }

    llOwnerSay(testName+": "+conclusion);        
    llSetText("",<1.0,1.0,1.0>,1.0);
}

string longString = "CKbfXmklN4jDlILbNgZcWeHvOupCAyrZkZW1UmXzD2QUgUhlO13L14apDFb5CecAyAQAPZAteA7V8vpMS9BiGyGjButGvy4qG01pAAQPmb1HVNOwtoLKPIWco9ZkhTCZkUzZmlgfHlfSMZLek6weUFn1h9oyaz9Ccu7ozJxLzzOlYme5ILoiYOppt1llgOcOnBu8MxoTStiKL7Gjx5H4bWtBmxtXGC1oE9nugZpgvPteogU3u5zmf3Gun3Rfh1h8PzmvFtzIaRZE0VfBONv47KZKtO0D7zMcfYJkPq7iR8lBRxmBCysObNPbGBKGrT6s5zUUjm38KHn5q8ukwZ2BZtjbmTCKNUKSgCzHuDCKXfh1yLBXDjQGooemFPNbczW1OEawY8Voi0O7nSFzfJJGoJqBcaHJzOT30FgSlzoZoamD7EgceSErjYJLYAoXJAgWOqeU22hTtl7iHfxjVrafQfOobyUTpH1Zjk9STXpGTzuR62N4HQJxFz9BfZf7S02xAJtotg6zopUTak7x1NQ0kSUFB8ZeDLzHykWxPi5C1CTQCiS4aHnDggEy455zo4ifiLzFNbBo7BW0XTqIJMp5w67kLMvScewY4KoJfvCfRfOW90ETb8kb7OBGSt4WMGvzFzfh3F8CU16oAmUESCQoYcrb7VqJfrUfKbvvPy6vRIfS70981uBI0RKZKg2jIGaCYUG30DzA662zrqfAqkg6eXqAF4JSiZfXRVImpLEfnYUZh7e573OFq8xJhq8BYAFQxPxKKts3YBTA2I42Dq0zq3SvK451CHXjwc1cpACEsLB0Cg8wx093fMi6GyFzR06aR1Cg8zQkl7mYbS2yhq1x7bMUqcklMZgui5t9LFG7RjPhetnnG4CtBzyDcJutSShAqOc3UhnM4w8cho0OshnpgwgR4ebA3fwbubkLyqsX6yFE0w7WKzMqfaSvPttoi1uVtno6KRCg7O71m4DI85uAl7VPjlsyitYNjjxFlRP6blIikaoLl8pmf3eDmFUperIQ";

default
{
    state_entry()
    {
        llOwnerSay("Touch to run test suite");
    }

    touch_start(integer total_number)
    {
        doTest("SHA-3 224 Empty",ALGORITHM_SHA3, 224, 0, "", "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7");
        doTest("SHA-3 512", ALGORITHM_SHA3, 512, 0, "The quick brown fox jumps over the lazy dog", "01dedd5de4ef14642445ba5f5b97c15e47b9ad931326e4b0727cd94cefc44fff23f07bf543139939b49128caf436dc1bdee54fcb24023a08d9403f9b4bf0d450");
        doTest("SHA-3 512 Cascade", ALGORITHM_SHA3, 512, 0, "The quick brown fox jumps over the lazy dog.", "18f4f4bd419603f95538837003d9d254c26c23765565162247483f65c50303597bc9ce4d289f21d1c2f1f458828e33dc442100331b35e7eb031b5d38ba6460f8");
        doTest("SHA-3 512 Empty", ALGORITHM_SHA3, 512, 0, "", "a69f73cca23a9ac5c8b567dc185a756e97c982164fe25859e0d1dcc1475c80a615b2123af1f5f94c11e3e9402c3ac558f500199d95b6d3e301758586281dcd26");
        doTest("SHA-3 512 Unicode",ALGORITHM_SHA3, 512, 0, "中文", "059bbe2efc50cc30e4d8ec5a96be697e2108fcbf9193e1296192eddabc13b143c0120d059399a13d0d42651efe23a6c1ce2d1efb576c5b207fa2516050505af7");
        doTest("SHA-3 512 Long",ALGORITHM_SHA3, 512, 0, longString, "7e8452e1a742af7170b1b85ef1743e0cac3e8f1dd11ffb6a0657641b813289b1a3efcc76a9d781e5c55400d8c337d437aa43d43ee6694d18814c76f8504a70cd");     


        doTest("SHA-3 384", ALGORITHM_SHA3, 384, 0, "The quick brown fox jumps over the lazy dog", "7063465e08a93bce31cd89d2e3ca8f602498696e253592ed26f07bf7e703cf328581e1471a7ba7ab119b1a9ebdf8be41");
        doTest("SHA-3 384 Cascade",ALGORITHM_SHA3, 384, 0, "The quick brown fox jumps over the lazy dog.", "1a34d81695b622df178bc74df7124fe12fac0f64ba5250b78b99c1273d4b080168e10652894ecad5f1f4d5b965437fb9");
        doTest("SHA-3 384 Empty", ALGORITHM_SHA3, 384, 0, "", "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004");
        doTest("SHA-3 384 Unicode",ALGORITHM_SHA3, 384, 0, "中文", "9fb5b99e3c546f2738dcd50a14e9aef9c313800c1bf8cf76bc9b2c3a23307841364c5a2d0794702662c5796fb72f5432");
        doTest("SHA-3 384 Long", ALGORITHM_SHA3, 384, 0, longString, "683009d6ebe8596b77142ace13ac0dfc3b640bdbc437f848a41dc11e7b36db49bc4c648f2fff887e49b1ec48e47bd457");

        doTest("SHA-3 256",ALGORITHM_SHA3, 256, 0, "The quick brown fox jumps over the lazy dog", "69070dda01975c8c120c3aada1b282394e7f032fa9cf32f4cb2259a0897dfc04");
        doTest("SHA-3 256 Cascade",ALGORITHM_SHA3, 256, 0, "The quick brown fox jumps over the lazy dog.", "a80f839cd4f83f6c3dafc87feae470045e4eb0d366397d5c6ce34ba1739f734d");
        doTest("SHA-3 256 Empty",ALGORITHM_SHA3, 256, 0, "", "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a");        ;
        doTest("SHA-3 256 Unicode",ALGORITHM_SHA3, 256, 0, "中文", "ac5305da3d18be1aed44aa7c70ea548da243a59a5fd546f489348fd5718fb1a0");
        doTest("SHA-3 256 Long",ALGORITHM_SHA3, 256, 0, longString, "070ca9c7ea03e907ace05f976db311c85e26f2ccf1f00c8db8e222d1ae336ca9");

        doTest("SHA-3 224",ALGORITHM_SHA3, 224, 0, "The quick brown fox jumps over the lazy dog", "d15dadceaa4d5d7bb3b48f446421d542e08ad8887305e28d58335795");
        doTest("SHA-3 224 Cascade",ALGORITHM_SHA3, 224, 0, "The quick brown fox jumps over the lazy dog.", "2d0708903833afabdd232a20201176e8b58c5be8a6fe74265ac54db0");
        doTest("SHA-3 224 Empty",ALGORITHM_SHA3, 224, 0, "", "6b4e03423667dbb73b6e15454f0eb1abd4597f9a1b078e3f5b5a6bc7");
        doTest("SHA-3 224 Unicode",ALGORITHM_SHA3, 224, 0, "中文", "106d169e10b61c2a2a05554d3e631ec94467f8316640f29545d163ee");
        doTest("SHA-3 224 Long",ALGORITHM_SHA3, 224, 0, longString, "1ea077c39a1e88ae715458f29fc580ca3e94a7d47dcdd829ac5e68af");
        
        doTest("Keccak 512",ALGORITHM_KECCAK, 512, 0, "The quick brown fox jumps over the lazy dog", "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609");
        doTest("Keccak 512 Cascade",ALGORITHM_KECCAK, 512, 0, "The quick brown fox jumps over the lazy dog.", "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760");
        doTest("Keccak 512 Empty",ALGORITHM_KECCAK, 512, 0, "", "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e");
        doTest("Keccak 512 Unicode",ALGORITHM_KECCAK, 512, 0, "中文", "2f6a1bd50562230229af34b0ccf46b8754b89d23ae2c5bf7840b4acfcef86f87395edc0a00b2bfef53bafebe3b79de2e3e01cbd8169ddbb08bde888dcc893524");
        
        doTest("Keccak 384",ALGORITHM_KECCAK, 384, 0, "The quick brown fox jumps over the lazy dog", "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3");
        doTest("Keccak 384 Cascade",ALGORITHM_KECCAK, 384, 0, "The quick brown fox jumps over the lazy dog.", "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b");
        doTest("Keccak 384 Empty",ALGORITHM_KECCAK, 384, 0, "", "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff");
        doTest("Keccak 384 Unicode",ALGORITHM_KECCAK, 384, 0, "中文", "743f64bb7544c6ed923be4741b738dde18b7cee384a3a09c4e01acaaac9f19222cdee137702bd3aa05dc198373d87d6c");

        doTest("Keccak 256",ALGORITHM_KECCAK, 256, 0, "The quick brown fox jumps over the lazy dog", "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15");
        doTest("Keccak 256 Cascade",ALGORITHM_KECCAK, 256, 0, "The quick brown fox jumps over the lazy dog.", "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d");
        doTest("Keccak 256 Empty",ALGORITHM_KECCAK, 256, 0, "", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470");
        doTest("Keccak 256 Unicode",ALGORITHM_KECCAK, 256, 0, "中文", "70a2b6579047f0a977fcb5e9120a4e07067bea9abb6916fbc2d13ffb9a4e4eee");

        doTest("Keccak 224",ALGORITHM_KECCAK, 224, 0, "The quick brown fox jumps over the lazy dog", "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe");
        doTest("Keccak 224 Cascade",ALGORITHM_KECCAK, 224, 0, "The quick brown fox jumps over the lazy dog.", "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab");
        doTest("Keccak 224 Empty",ALGORITHM_KECCAK, 224, 0, "", "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd");
        doTest("Keccak 224 Unicode",ALGORITHM_KECCAK, 224, 0, "中文", "7bc2a0b6e7e0a055a61e4f731e2944b560f41ff98967dcbf4bbf77a5");
        
        doTest("Shake 256 (512)",ALGORITHM_SHAKE, 256, 512, "The quick brown fox jumps over the lazy dog", "2f671343d9b2e1604dc9dcf0753e5fe15c7c64a0d283cbbf722d411a0e36f6ca1d01d1369a23539cd80f7c054b6e5daf9c962cad5b8ed5bd11998b40d5734442");
        doTest("Shake 256 (512) Cascade",ALGORITHM_SHAKE, 256, 512, "The quick brown fox jumps over the lazy dog.", "bd225bfc8b255f3036f0c8866010ed0053b5163a3cae111e723c0c8e704eca4e5d0f1e2a2fa18c8a219de6b88d5917ff5dd75b5fb345e7409a3b333b508a65fb");
        doTest("Shake 256 (512) Empty",ALGORITHM_SHAKE, 256, 512, "", "46b9dd2b0ba88d13233b3feb743eeb243fcd52ea62b81b82b50c27646ed5762fd75dc4ddd8c0f200cb05019d67b592f6fc821c49479ab48640292eacb3b7c4be");
        doTest("Shake 256 (512) Unicode",ALGORITHM_SHAKE, 256, 512, "中文", "23c0e9f7f5e9863798dcc6de066ba3bc858fcf1652fbb19aeb0d45b049aae5b3cff3f2ee0f33ec00b4527c25e13c8fdf6abf56a4e4c18821fa9afa7d5cb5609d");
        
        doTest("Shake 128 (256)",ALGORITHM_SHAKE, 128, 256, "The quick brown fox jumps over the lazy dog", "f4202e3c5852f9182a0430fd8144f0a74b95e7417ecae17db0f8cfeed0e3e66e");
        doTest("Shake 128 (256) Cascade",ALGORITHM_SHAKE, 128, 256, "The quick brown fox jumps over the lazy dog.", "634069e6b13c3af64c57f05babf5911b6acf1d309b9624fc92b0c0bd9f27f538");
        doTest("Shake 128 (256) Empty",ALGORITHM_SHAKE, 128, 256, "", "7f9c2ba4e88f827d616045507605853ed73b8093f6efbc88eb1a6eacfa66ef26");
        doTest("Shake 128 (256) Unicode",ALGORITHM_SHAKE, 128, 256, "中文", "d001a1cbe144d95604a9483407bdfbe078421a5f5a91a3de3465182cd11df868");
        
        llOwnerSay("("+(string)passed+"/"+(string)total+") tests passed");
        
    }
}