/*
 * Copyright (c) 2012-2020 MIRACL UK Ltd.
 *
 * This file is part of MIRACL Core
 * (see https://github.com/miracl/core).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Implementation of the Secure Hashing Algorithm (SHA-256/384/512 and SHA3)
 *
 * Generates a message digest. It should be impossible to come
 * come up with two messages that hash to the same value ("collision free").
 *
 * For use with byte-oriented messages only. Could/Should be speeded
 * up by unwinding loops in HASH_transform(), and assembly patches.
 */

#include "arch.h"
#include "core.h"

using namespace core;

#define H0_256 0x6A09E667L
#define H1_256 0xBB67AE85L
#define H2_256 0x3C6EF372L
#define H3_256 0xA54FF53AL
#define H4_256 0x510E527FL
#define H5_256 0x9B05688CL
#define H6_256 0x1F83D9ABL
#define H7_256 0x5BE0CD19L

static const unsign32 K_256[64] =
{
    0x428a2f98L, 0x71374491L, 0xb5c0fbcfL, 0xe9b5dba5L, 0x3956c25bL, 0x59f111f1L, 0x923f82a4L, 0xab1c5ed5L,
    0xd807aa98L, 0x12835b01L, 0x243185beL, 0x550c7dc3L, 0x72be5d74L, 0x80deb1feL, 0x9bdc06a7L, 0xc19bf174L,
    0xe49b69c1L, 0xefbe4786L, 0x0fc19dc6L, 0x240ca1ccL, 0x2de92c6fL, 0x4a7484aaL, 0x5cb0a9dcL, 0x76f988daL,
    0x983e5152L, 0xa831c66dL, 0xb00327c8L, 0xbf597fc7L, 0xc6e00bf3L, 0xd5a79147L, 0x06ca6351L, 0x14292967L,
    0x27b70a85L, 0x2e1b2138L, 0x4d2c6dfcL, 0x53380d13L, 0x650a7354L, 0x766a0abbL, 0x81c2c92eL, 0x92722c85L,
    0xa2bfe8a1L, 0xa81a664bL, 0xc24b8b70L, 0xc76c51a3L, 0xd192e819L, 0xd6990624L, 0xf40e3585L, 0x106aa070L,
    0x19a4c116L, 0x1e376c08L, 0x2748774cL, 0x34b0bcb5L, 0x391c0cb3L, 0x4ed8aa4aL, 0x5b9cca4fL, 0x682e6ff3L,
    0x748f82eeL, 0x78a5636fL, 0x84c87814L, 0x8cc70208L, 0x90befffaL, 0xa4506cebL, 0xbef9a3f7L, 0xc67178f2L
};

#define PAD  0x80
#define ZERO 0

/* functions */

#define S(m,n,x) (((x)>>n) | ((x)<<(m-n)))
#define R(n,x) ((x)>>n)

#define Ch(x,y,z)  ((x&y)^(~(x)&z))
#define Maj(x,y,z) ((x&y)^(x&z)^(y&z))
#define Sig0_256(x)    (S(32,2,x)^S(32,13,x)^S(32,22,x))
#define Sig1_256(x)    (S(32,6,x)^S(32,11,x)^S(32,25,x))
#define theta0_256(x)  (S(32,7,x)^S(32,18,x)^R(3,x))
#define theta1_256(x)  (S(32,17,x)^S(32,19,x)^R(10,x))

#define Sig0_512(x)    (S(64,28,x)^S(64,34,x)^S(64,39,x))
#define Sig1_512(x)    (S(64,14,x)^S(64,18,x)^S(64,41,x))
#define theta0_512(x)  (S(64,1,x)^S(64,8,x)^R(7,x))
#define theta1_512(x)  (S(64,19,x)^S(64,61,x)^R(6,x))


/* SU= 72 */
static void HASH256_transform(hash256 *sh)
{
    /* basic transformation step */
    unsign32 a, b, c, d, e, f, g, h, t1, t2;
    int j;
    for (j = 16; j < 64; j++)
        sh->w[j] = theta1_256(sh->w[j - 2]) + sh->w[j - 7] + theta0_256(sh->w[j - 15]) + sh->w[j - 16];

    a = sh->h[0];
    b = sh->h[1];
    c = sh->h[2];
    d = sh->h[3];
    e = sh->h[4];
    f = sh->h[5];
    g = sh->h[6];
    h = sh->h[7];

    for (j = 0; j < 64; j++)
    {
        /* 64 times - mush it up */
        t1 = h + Sig1_256(e) + Ch(e, f, g) + K_256[j] + sh->w[j];
        t2 = Sig0_256(a) + Maj(a, b, c);
        h = g;
        g = f;
        f = e;
        e = d + t1;
        d = c;
        c = b;
        b = a;
        a = t1 + t2;
    }

    sh->h[0] += a;
    sh->h[1] += b;
    sh->h[2] += c;
    sh->h[3] += d;
    sh->h[4] += e;
    sh->h[5] += f;
    sh->h[6] += g;
    sh->h[7] += h;
}

/* Initialise Hash function */
void core::HASH256_init(hash256 *sh)
{
    /* re-initialise */
    int i;
    for (i = 0; i < 64; i++) sh->w[i] = 0L;
    sh->length[0] = sh->length[1] = 0L;
    sh->h[0] = H0_256;
    sh->h[1] = H1_256;
    sh->h[2] = H2_256;
    sh->h[3] = H3_256;
    sh->h[4] = H4_256;
    sh->h[5] = H5_256;
    sh->h[6] = H6_256;
    sh->h[7] = H7_256;

    sh->hlen = 32;
}

/* process a single byte */
void core::HASH256_process(hash256 *sh, int byt)
{
    /* process the next message byte */
    int cnt;
    cnt = (int)((sh->length[0] / 32) % 16);

    sh->w[cnt] <<= 8;
    sh->w[cnt] |= (unsign32)(byt & 0xFF);

    sh->length[0] += 8;
    if (sh->length[0] == 0L)
    {
        sh->length[1]++;
        sh->length[0] = 0L;
    }
    if ((sh->length[0] % 512) == 0) HASH256_transform(sh);
}

/* SU= 24 */
/* Generate 32-byte final Hash */
void core::HASH256_hash(hash256 *sh, char *digest)
{
    /* pad message and finish - supply digest */
    int i;
    unsign32 len0, len1;
    len0 = sh->length[0];
    len1 = sh->length[1];
    HASH256_process(sh, PAD);
    while ((sh->length[0] % 512) != 448) HASH256_process(sh, ZERO);
    sh->w[14] = len1;
    sh->w[15] = len0;
    HASH256_transform(sh);
    for (i = 0; i < sh->hlen; i++)
    {
        /* convert to bytes */
        digest[i] = (char)((sh->h[i / 4] >> (8 * (3 - i % 4))) & 0xffL);
    }
    HASH256_init(sh);
}

/* return 32-byte intermediate hash */
void core::HASH256_continuing_hash(hash256 *sh,char *digest)
{
    hash256 cp=*sh;
    HASH256_hash(&cp,digest);
}


#define H0_512 0x6a09e667f3bcc908
#define H1_512 0xbb67ae8584caa73b
#define H2_512 0x3c6ef372fe94f82b
#define H3_512 0xa54ff53a5f1d36f1
#define H4_512 0x510e527fade682d1
#define H5_512 0x9b05688c2b3e6c1f
#define H6_512 0x1f83d9abfb41bd6b
#define H7_512 0x5be0cd19137e2179

#define H8_512 0xcbbb9d5dc1059ed8
#define H9_512 0x629a292a367cd507
#define HA_512 0x9159015a3070dd17
#define HB_512 0x152fecd8f70e5939
#define HC_512 0x67332667ffc00b31
#define HD_512 0x8eb44a8768581511
#define HE_512 0xdb0c2e0d64f98fa7
#define HF_512 0x47b5481dbefa4fa4

/* */

static const unsign64 K_512[80] =
{
    0x428a2f98d728ae22 , 0x7137449123ef65cd , 0xb5c0fbcfec4d3b2f , 0xe9b5dba58189dbbc ,
    0x3956c25bf348b538 , 0x59f111f1b605d019 , 0x923f82a4af194f9b , 0xab1c5ed5da6d8118 ,
    0xd807aa98a3030242 , 0x12835b0145706fbe , 0x243185be4ee4b28c , 0x550c7dc3d5ffb4e2 ,
    0x72be5d74f27b896f , 0x80deb1fe3b1696b1 , 0x9bdc06a725c71235 , 0xc19bf174cf692694 ,
    0xe49b69c19ef14ad2 , 0xefbe4786384f25e3 , 0x0fc19dc68b8cd5b5 , 0x240ca1cc77ac9c65 ,
    0x2de92c6f592b0275 , 0x4a7484aa6ea6e483 , 0x5cb0a9dcbd41fbd4 , 0x76f988da831153b5 ,
    0x983e5152ee66dfab , 0xa831c66d2db43210 , 0xb00327c898fb213f , 0xbf597fc7beef0ee4 ,
    0xc6e00bf33da88fc2 , 0xd5a79147930aa725 , 0x06ca6351e003826f , 0x142929670a0e6e70 ,
    0x27b70a8546d22ffc , 0x2e1b21385c26c926 , 0x4d2c6dfc5ac42aed , 0x53380d139d95b3df ,
    0x650a73548baf63de , 0x766a0abb3c77b2a8 , 0x81c2c92e47edaee6 , 0x92722c851482353b ,
    0xa2bfe8a14cf10364 , 0xa81a664bbc423001 , 0xc24b8b70d0f89791 , 0xc76c51a30654be30 ,
    0xd192e819d6ef5218 , 0xd69906245565a910 , 0xf40e35855771202a , 0x106aa07032bbd1b8 ,
    0x19a4c116b8d2d0c8 , 0x1e376c085141ab53 , 0x2748774cdf8eeb99 , 0x34b0bcb5e19b48a8 ,
    0x391c0cb3c5c95a63 , 0x4ed8aa4ae3418acb , 0x5b9cca4f7763e373 , 0x682e6ff3d6b2b8a3 ,
    0x748f82ee5defb2fc , 0x78a5636f43172f60 , 0x84c87814a1f0ab72 , 0x8cc702081a6439ec ,
    0x90befffa23631e28 , 0xa4506cebde82bde9 , 0xbef9a3f7b2c67915 , 0xc67178f2e372532b ,
    0xca273eceea26619c , 0xd186b8c721c0c207 , 0xeada7dd6cde0eb1e , 0xf57d4f7fee6ed178 ,
    0x06f067aa72176fba , 0x0a637dc5a2c898a6 , 0x113f9804bef90dae , 0x1b710b35131c471b ,
    0x28db77f523047d84 , 0x32caab7b40c72493 , 0x3c9ebe0a15c9bebc , 0x431d67c49c100d4c ,
    0x4cc5d4becb3e42b6 , 0x597f299cfc657e2a , 0x5fcb6fab3ad6faec , 0x6c44198c4a475817
};

static void HASH512_transform(hash512 *sh)
{
    /* basic transformation step */
    unsign64 a, b, c, d, e, f, g, h, t1, t2;
    int j;
    for (j = 16; j < 80; j++)
        sh->w[j] = theta1_512(sh->w[j - 2]) + sh->w[j - 7] + theta0_512(sh->w[j - 15]) + sh->w[j - 16];

    a = sh->h[0];
    b = sh->h[1];
    c = sh->h[2];
    d = sh->h[3];
    e = sh->h[4];
    f = sh->h[5];
    g = sh->h[6];
    h = sh->h[7];

    for (j = 0; j < 80; j++)
    {
        /* 80 times - mush it up */
        t1 = h + Sig1_512(e) + Ch(e, f, g) + K_512[j] + sh->w[j];
        t2 = Sig0_512(a) + Maj(a, b, c);
        h = g;
        g = f;
        f = e;
        e = d + t1;
        d = c;
        c = b;
        b = a;
        a = t1 + t2;
    }
    sh->h[0] += a;
    sh->h[1] += b;
    sh->h[2] += c;
    sh->h[3] += d;
    sh->h[4] += e;
    sh->h[5] += f;
    sh->h[6] += g;
    sh->h[7] += h;
}

void core::HASH384_init(hash384 *sh)
{
    /* re-initialise */
    int i;
    for (i = 0; i < 80; i++) sh->w[i] = 0;
    sh->length[0] = sh->length[1] = 0;
    sh->h[0] = H8_512;
    sh->h[1] = H9_512;
    sh->h[2] = HA_512;
    sh->h[3] = HB_512;
    sh->h[4] = HC_512;
    sh->h[5] = HD_512;
    sh->h[6] = HE_512;
    sh->h[7] = HF_512;

    sh->hlen = 48;
}

void core::HASH384_process(hash384 *sh, int byt)
{
    /* process the next message byte */
    HASH512_process(sh, byt);
}

void core::HASH384_hash(hash384 *sh, char *digest)
{
    /* pad message and finish - supply digest */
    HASH512_hash(sh, digest);
}

/* return intermediate hash */
void core::HASH384_continuing_hash(hash384 *sh,char *digest)
{
    hash384 cp=*sh;
    HASH384_hash(&cp,digest);
}

void core::HASH512_init(hash512 *sh)
{
    /* re-initialise */
    int i;

    for (i = 0; i < 80; i++) sh->w[i] = 0;
    sh->length[0] = sh->length[1] = 0;
    sh->h[0] = H0_512;
    sh->h[1] = H1_512;
    sh->h[2] = H2_512;
    sh->h[3] = H3_512;
    sh->h[4] = H4_512;
    sh->h[5] = H5_512;
    sh->h[6] = H6_512;
    sh->h[7] = H7_512;

    sh->hlen = 64;
}

void core::HASH512_process(hash512 *sh, int byt)
{
    /* process the next message byte */
    int cnt;

    cnt = (int)((sh->length[0] / 64) % 16);

    sh->w[cnt] <<= 8;
    sh->w[cnt] |= (unsign64)(byt & 0xFF);

    sh->length[0] += 8;
    if (sh->length[0] == 0L)
    {
        sh->length[1]++;
        sh->length[0] = 0L;
    }
    if ((sh->length[0] % 1024) == 0) HASH512_transform(sh);
}

void core::HASH512_hash(hash512 *sh, char *digest)
{
    /* pad message and finish - supply digest */
    int i;
    unsign64 len0, len1;
    len0 = sh->length[0];
    len1 = sh->length[1];
    HASH512_process(sh, PAD);
    while ((sh->length[0] % 1024) != 896) HASH512_process(sh, ZERO);
    sh->w[14] = len1;
    sh->w[15] = len0;
    HASH512_transform(sh);
    for (i = 0; i < sh->hlen; i++)
    {
        /* convert to bytes */
        digest[i] = (char)((sh->h[i / 8] >> (8 * (7 - i % 8))) & 0xffL);
    }
    HASH512_init(sh);
}

/* return intermediate hash */
void core::HASH512_continuing_hash(hash512 *sh,char *digest)
{
    hash512 cp=*sh;
    HASH512_hash(&cp,digest);
}

/* SHA3 */

#define SHA3_ROUNDS 24
#define rotl(x,n) (((x)<<n) | ((x)>>(64-n)))

/* round constants */

static const unsign64 RC[24] = {
    0x0000000000000001UL, 0x0000000000008082UL, 0x800000000000808AUL, 0x8000000080008000UL,
    0x000000000000808BUL, 0x0000000080000001UL, 0x8000000080008081UL, 0x8000000000008009UL,
    0x000000000000008AUL, 0x0000000000000088UL, 0x0000000080008009UL, 0x000000008000000AUL,
    0x000000008000808BUL, 0x800000000000008BUL, 0x8000000000008089UL, 0x8000000000008003UL,
    0x8000000000008002UL, 0x8000000000000080UL, 0x000000000000800AUL, 0x800000008000000AUL,
    0x8000000080008081UL, 0x8000000000008080UL, 0x0000000080000001UL, 0x8000000080008008UL
};

static void SHA3_transform(sha3 *sh)
{
    int k;
    unsign64 B00,B01,B02,B03,B04,B10,B11,B12,B13,B14,B20,B21,B22,B23,B24,B30,B31,B32,B33,B34,B40,B41,B42,B43,B44;
    unsign64 C0,C1,C2,C3,C4,D0,D1,D2,D3,D4;

    for (k = 0; k < SHA3_ROUNDS; k++)
    {

        C0=sh->S[0] ^ sh->S[5] ^ sh->S[10] ^ sh->S[15] ^ sh->S[20];
        C1=sh->S[1] ^ sh->S[6] ^ sh->S[11] ^ sh->S[16] ^ sh->S[21];
        C2=sh->S[2] ^ sh->S[7] ^ sh->S[12] ^ sh->S[17] ^ sh->S[22];
        C3=sh->S[3] ^ sh->S[8] ^ sh->S[13] ^ sh->S[18] ^ sh->S[23];
        C4=sh->S[4] ^ sh->S[9] ^ sh->S[14] ^ sh->S[19] ^ sh->S[24];

        D0 = C4 ^ rotl(C1, 1);
        D1 = C0 ^ rotl(C2, 1);
        D2 = C1 ^ rotl(C3, 1);
        D3 = C2 ^ rotl(C4, 1);
        D4 = C3 ^ rotl(C0, 1);

        B00 =      sh->S[0]^D0;
        B02 = rotl(sh->S[1]^D1, 1);
        B04 = rotl(sh->S[2]^D2, 62);
        B01 = rotl(sh->S[3]^D3, 28);
        B03 = rotl(sh->S[4]^D4, 27);

        B13 = rotl(sh->S[5]^D0, 36);
        B10 = rotl(sh->S[6]^D1, 44);
        B12 = rotl(sh->S[7]^D2, 6);
        B14 = rotl(sh->S[8]^D3, 55);
        B11 = rotl(sh->S[9]^D4, 20);

        B21 = rotl(sh->S[10]^D0, 3);
        B23 = rotl(sh->S[11]^D1, 10);
        B20 = rotl(sh->S[12]^D2, 43);
        B22 = rotl(sh->S[13]^D3, 25);
        B24 = rotl(sh->S[14]^D4, 39);

        B34 = rotl(sh->S[15]^D0, 41);
        B31 = rotl(sh->S[16]^D1, 45);
        B33 = rotl(sh->S[17]^D2, 15);
        B30 = rotl(sh->S[18]^D3, 21);
        B32 = rotl(sh->S[19]^D4, 8);

        B42 = rotl(sh->S[20]^D0, 18);
        B44 = rotl(sh->S[21]^D1, 2);
        B41 = rotl(sh->S[22]^D2, 61);
        B43 = rotl(sh->S[23]^D3, 56);
        B40 = rotl(sh->S[24]^D4, 14);    

        sh->S[0]=B00^(~B10&B20);
        sh->S[1]=B10^(~B20&B30);
        sh->S[2]=B20^(~B30&B40);
        sh->S[3]=B30^(~B40&B00);
        sh->S[4]=B40^(~B00&B10);

        sh->S[5]=B01^(~B11&B21);
        sh->S[6]=B11^(~B21&B31);
        sh->S[7]=B21^(~B31&B41);
        sh->S[8]=B31^(~B41&B01);
        sh->S[9]=B41^(~B01&B11);

        sh->S[10]=B02^(~B12&B22);
        sh->S[11]=B12^(~B22&B32);
        sh->S[12]=B22^(~B32&B42);
        sh->S[13]=B32^(~B42&B02);
        sh->S[14]=B42^(~B02&B12);

        sh->S[15]=B03^(~B13&B23);
        sh->S[16]=B13^(~B23&B33);
        sh->S[17]=B23^(~B33&B43);
        sh->S[18]=B33^(~B43&B03);
        sh->S[19]=B43^(~B03&B13);

        sh->S[20]=B04^(~B14&B24);
        sh->S[21]=B14^(~B24&B34);
        sh->S[22]=B24^(~B34&B44);
        sh->S[23]=B34^(~B44&B04);
        sh->S[24]=B44^(~B04&B14);

        sh->S[0] ^= RC[k];
    }
}

/* Re-Initialize. olen is output length in bytes -
   should be 28, 32, 48 or 64 (224, 256, 384, 512 bits resp.) */

void core::SHA3_init(sha3 *sh, int olen)
{
    int i;
    for (i = 0; i < 25; i++)
        sh->S[i] = 0;           /* 5x5x8 bytes = 200 bytes of state */

    sh->length = 0;
    sh->len = olen;
    sh->rate = 200 - 2 * olen; /* number of bytes consumed in one gulp. Note that some bytes in the
                            state ("capacity") are not touched. Gulps are smaller for larger digests.
                            Important that olen<rate */
}

/* process a single byte */
void core::SHA3_process(sha3 *sh, int byt)
{
    int cnt = (int)(sh->length);
    int b = cnt % 8;
    cnt /= 8;
    sh->S[cnt] ^= ((unsign64)(byt & 0xff) << (8 * b));
    sh->length++;
    if (sh->length == sh->rate)
    {
        sh->length=0;
        SHA3_transform(sh);
    }
}

/* squeeze the sponge */
void core::SHA3_squeeze(sha3 *sh, char *buff, int len)
{
    int i, j, k, m = 0;
    unsign64 el;
    int nb=len/sh->rate;
// squeeze out full blocks
    for (j=0;j<nb;j++ )
    {
        for (i=0;i<sh->rate/8;i++)
        {
            el=sh->S[i];
            for (k=0;k<8;k++)
            {
               buff[m++] = (el & 0xff);
               el >>= 8;
            }
        }
        SHA3_transform(sh);    
    }
   
// squeeze out whats left
    i=0;
    while (m<len)
    {
        el = sh->S[i++];
        for (k = 0; k < 8; k++)
        {
            buff[m++] = (el & 0xff);
            if (m >= len) break;
            el >>= 8;
        }    
    } 
}

void core::SHA3_hash(sha3 *sh, char *digest)
{   /* generate a SHA3 hash of appropriate size */
    int q = sh->rate - sh->length;
    if (q == 1) SHA3_process(sh, 0x86);
    else
    {
        SHA3_process(sh, 0x06);  /* 0x06 for SHA-3 */
        while (sh->length != sh->rate - 1) SHA3_process(sh, 0x00);
        SHA3_process(sh, 0x80); /* this will force a final transform */
    }
    SHA3_squeeze(sh, digest, sh->len);
}

/* return intermediate hash */
void core::SHA3_continuing_hash(sha3 *sh,char *digest)
{
    sha3 cp=*sh;
    SHA3_hash(&cp,digest);
}

void core::SHA3_shake(sha3 *sh, char *digest, int len)
{   /* SHAKE out a buffer of variable length len */
    int q = sh->rate - sh->length;
    if (q == 1) SHA3_process(sh, 0x9f);
    else
    {
        SHA3_process(sh, 0x1f);  // 0x06 for SHA-3 !!!!
        while (sh->length != sh->rate - 1) SHA3_process(sh, 0x00);
        SHA3_process(sh, 0x80); /* this will force a final transform */
    }
    SHA3_squeeze(sh, digest, len);
}

/* return intermediate hash */
void core::SHA3_continuing_shake(sha3 *sh,char *digest,int len)
{
    sha3 cp=*sh;
    SHA3_shake(&cp,digest,len);
}

/* test program: should produce digest

160 bit

84983e44 1c3bd26e baae4aa1 f95129e5 e54670f1

256 bit

248d6a61 d20638b8 e5c02693 0c3e6039 a33ce459 64ff2167 f6ecedd4 19db06c1

512 bit

8e959b75dae313da 8cf4f72814fc143f 8f7779c6eb9f7fa1 7299aeadb6889018
501d289e4900f7e4 331b99dec4b5433a c7d329eeb6dd2654 5e96e55b874be909

384 bit

09330c33f71147e8 3d192fc782cd1b47 53111b173b3b05d2 2fa08086e3b0f712
fcc7c71a557e2db9 66c3e9fa91746039
*/
/*
#include <stdio.h>

char test160[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
char test256[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq";
char test512[]="abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu";

int main()
{
    char digest[100];
    int i;

    hash256 sh256;
    hash384 sh384;
    hash512 sh512;
    sha3 SHA3;

    HASH256_init(&sh256);
    for (i=0;test256[i]!=0;i++) HASH256_process(&sh256,test256[i]);
    HASH256_hash(&sh256,digest);
    for (i=0;i<32;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    HASH384_init(&sh384);
    for (i=0;test512[i]!=0;i++) HASH384_process(&sh384,test512[i]);
    HASH384_hash(&sh384,digest);
    for (i=0;i<48;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    HASH512_init(&sh512);
    for (i=0;test512[i]!=0;i++) HASH512_process(&sh512,test512[i]);
    HASH512_hash(&sh512,digest);
    for (i=0;i<64;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    SHA3_init(&SHA3,SHA3_HASH256);
    for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]);
    SHA3_hash(&SHA3,digest);
    for (i=0;i<32;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    SHA3_init(&SHA3,SHA3_HASH512);
    for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]);
    SHA3_hash(&SHA3,digest);
    for (i=0;i<64;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    SHA3_init(&SHA3,SHAKE256);
    for (i=0;test512[i]!=0;i++) SHA3_process(&SHA3,test512[i]);
    SHA3_shake(&SHA3,digest,72);
    for (i=0;i<72;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");


    return 0;
}

*/
