Difference between revisions of "SHA-3"

From Second Life Wiki
Jump to navigation Jump to search
m
 
Line 3: Line 3:


Anyone who has time to go through and optimise this is more than welcome to do so! Processing speed is roughly 391 characters per second on an unladen sim in September 2022 (improved from 100 CPS in 2017).
Anyone who has time to go through and optimise this is more than welcome to do so! Processing speed is roughly 391 characters per second on an unladen sim in September 2022 (improved from 100 CPS in 2017).
Memory consumption of the script iself (with tests removed) is 28,072 bytes, and uses up to 6,842 bytes during execution.


View {{Wikipedia|SHA-3}} for more information.
View {{Wikipedia|SHA-3}} for more information.

Latest revision as of 03:51, 13 September 2022

Performs an SHA-3 Hash on the text. Similar to an MD5 hash, but significantly more secure. It supports all three versions of the algorithm - SHA-3, Keccak, SHAKE.

Anyone who has time to go through and optimise this is more than welcome to do so! Processing speed is roughly 391 characters per second on an unladen sim in September 2022 (improved from 100 CPS in 2017).

Memory consumption of the script iself (with tests removed) is 28,072 bytes, and uses up to 6,842 bytes during execution.

View "Wikipedia logo"SHA-3 for more information.

/////////////////////////////////////////////////////////////////////////////////
//
//      SHA-3 implementation by Casper Warden
//
//      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");
        
        llResetTime();
        digest(ALGORITHM_SHA3, 256, 0, "o5wBIVjk6mAmyO9SlmAM7IeP2HJqvgE6bBAbtlSsGpODF3xTOC6Gx3FrKfy17arbwvtguRYhjZ64U9nnkd4JgCYw4Kswz5c4f3Iul1bCZNYbeVDJQMZMn9AbBSNPd62T8LaMhBmYPqCgXgta4jmbWgjjYaBEtj6nhnQp4wVcrc95HuACtzWU8WPjwK6R3qpMDt1zA1zp9VcsH4FDsxk6ocmuEz7XUROANRRmD4LZZ9LFadI3kRCYThy1YZDzZyZFPtGv4yjbGXxuBh2PykksFN1QNiVMHGTq5ugb4dl8PBYgp5IP5lrDtnKYmA2LusKeePzLZ7Oib7Wr5NQgn10C0KE0tN5TXoWIupFi3beaKU3WnDf35mmeTAsYAJ1e0zq1nG03bue6Ayf9jlWhns0oABzX0Iar9NddRr49FHoIWeW20rCu5C9ln9QuOuwKm8djFrg43qYXIeDr3hDNfDe4blDv3Qvn1sDOTFeOWxSMgDYWSSITw8jzhsmcKyaz1juPsnuxUihhEMv6Fi2rcOjXuFb0GMzZ7dtY36N9yoDslJAx0B8sg05LKYABSnvYyw0K7TKurcNExUz24fvDYclWFDQ4cM1hpA9KgFZwMxgFQXoJTRwrtGSjwfcb3e3ZG7xWfhN7gnGNYEJJioEvH2qrYUC9c1PKfhlsC3lV7TPkWZFdGnEsThXjj9JaDHoWoEXmuAiFZeb1Di8MM9kvYCBtblZdjUv9boWSY0mbuYWj6mRCfnIpTXYd5hHI6J99UPLh2sQBmOy1SsrCk4R4PFMe3Jvxhi9wLYvzNFOoU6PavpBvqNFSxSkhl4wFnqu7XMWPSrXDRPCeckNNSWA5LgcF98oAcnvsSyEplu1EXgPdKj8Ba0HWHMG6iCzKOiZRgbzc9VZFCqbKtD1kgFuDA9KODQcJT4CdoCyJiNhvbgWljgfxwmqIOCUgIupSgZNq3vY8JbeOQvKstt1ed0xZsUjHYgqdKnj0CGvZgBtz6XCd");
        float endTime = llGetTime();
        
        llOwnerSay("("+(string)passed+"/"+(string)total+") tests passed");
        llOwnerSay("Benchmark: 1000 chars in " + (string)endTime + " seconds - " + (string)(1000 / endTime) + " characters per second");
    }
}