/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you 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)
 *
 * Generates a 256/384/512 bit 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 "amcl.h"


#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 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 HASH256_process(hash256 *sh,int byte)
{
    /* process the next message byte */
    int cnt;
//printf("byt= %x\n",byte);
    cnt=(int)((sh->length[0]/32)%16);

    sh->w[cnt]<<=8;
    sh->w[cnt]|=(unsign32)(byte&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 Hash */
void 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);
}


#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 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 HASH384_process(hash384 *sh,int byte)
{
    /* process the next message byte */
    HASH512_process(sh,byte);
}

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

void 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 HASH512_process(hash512 *sh,int byte)
{
    /* process the next message byte */
    int cnt;

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

    sh->w[cnt]<<=8;
    sh->w[cnt]|=(unsign64)(byte&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 HASH512_hash(hash512 *sh,char *hash)
{
    /* 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 */
        hash[i]=(char)((sh->h[i/8]>>(8*(7-i%8))) & 0xffL);
    }
    HASH512_init(sh);
}


/* 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>
#include "aracrypt.h"

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

int main()
{
    char digest[64];
    int i;
	hash160 sh160;
    hash256 sh256;
	hash384 sh384;
	hash512 sh512;

    HASH160_init(&sh160);
    for (i=0;test256[i]!=0;i++) HASH160_process(&sh160,test160[i]);
    HASH160_hash(&sh160,digest);
    for (i=0;i<20;i++) printf("%02x",(unsigned char)digest[i]);
    printf("\n");

    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");


    return 0;
}

*/
