/*
 * Crypto Hackers Tool Kit - http://www.cypherspace.org/crypto/
 *
 * Adam Back <adam@cypherspace.org>
 *
 * Implementation of Federal Information Processing Standards Publication
 * FIPS 180-1 (17 Apr 1995) which supersedes FIPS 180 (11 May 1993)
 *
 * Reference version optimised for clarity, and ease of comparison to the
 * standard (see fip-180.txt) no speed hacks
 *
 */

/* define VERBOSE to get output as in fip180-1.txt */

#if defined( VERBOSE )
    #include <stdio.h>
#endif
#include "sha1.h"
#include "endian.h"

#define min( x, y ) ( ( x ) < ( y ) ? ( x ) : ( y ) )

/* function used for rounds 0..19 */

static word32 F1( word32 B, word32 C, word32 D )
{
    return ( B & C ) | ( ~B & D );
}

/* function used for rounds 20..39 */

static word32 F2( word32 B, word32 C, word32 D )
{
    return ( B ^ C ^ D );
}

/* function used for rounds 40..59 */

static word32 F3( word32 B, word32 C, word32 D )
{
    return ( B & C ) | ( B & D ) | ( C & D );   
}

/* function used for rounds 60..79 */

static word32 F4( word32 B, word32 C, word32 D )
{
    return ( B ^ C ^ D );
}

/* array F of 80 functions */

typedef word32 ( *FuncPtr )( word32, word32, word32 );
FuncPtr F[ 80 ] = {
    F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,F1,
    F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,F2,
    F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,F3,
    F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4,F4
};


#define K1 0x5A827999  /* constant used for rounds 0..19 */
#define K2 0x6ED9EBA1  /* constant used for rounds 20..39 */
#define K3 0x8F1BBCDC  /* constant used for rounds 40..59 */
#define K4 0xCA62C1D6  /* constant used for rounds 60..79 */

/* array K of 80 constants */

word32 K[ 80 ] = {
    K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,K1,
    K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,K2,
    K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,K3,
    K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4,K4
};

#define H0 0x67452301
#define H1 0xEFCDAB89
#define H2 0x98BADCFE
#define H3 0x10325476
#define H4 0xC3D2E1F0

word32 SHA1_IV[ SHA1_DIGEST_WORDS ] = { H0, H1, H2, H3, H4 };

/* rotate X n bits left   ( X <<< n ) */

#define S( n, X ) (((X) << (n)) | ((X) >> (32 - (n))))

#if defined( VERBOSE )
int sha1_block;
#endif

void SHA1_init( SHA1_ctx* ctx )
{
#if defined( VERBOSE )
    sha1_block = 1;
#endif
    ctx->counter = 0;
    memcpy( ctx->H, SHA1_IV, SHA1_DIGEST_BYTES );
}

/* this is only used if you want to modify the IV */
/* ignore this function for purposes of the standard */

void SHA1_init_with_IV( SHA1_ctx* ctx, 
			const byte user_IV[ SHA1_DIGEST_BYTES ] )
{
#if defined( VERBOSE )
    sha1_block = 0;
#endif
    ctx->counter = 0;
    memcpy( ctx->H, user_IV, SHA1_DIGEST_BYTES );
    make_big_endian32( ctx->H, SHA1_DIGEST_WORDS );
}

void SHA1_transform( word32 H[ SHA1_DIGEST_WORDS ], 
		     const byte M[ SHA1_INPUT_BYTES ] )
{
    int t;
    word32 A = H[ 0 ];
    word32 B = H[ 1 ];
    word32 C = H[ 2 ];
    word32 D = H[ 3 ];
    word32 E = H[ 4 ];
    word32 TEMP;
    word32 W[ 80 ];

    memcpy( W, M, SHA1_INPUT_BYTES );
    make_big_endian32( W, SHA1_INPUT_WORDS );
    
#if defined( VERBOSE )
    if ( sha1_verbose )
    {
        fprintf( stderr, "Start processing block %d.  ", sha1_block );
        fprintf( stderr, "The words of block %d are\n", sha1_block );
        for ( t = 0; t < 16; t++ )
	{
            fprintf( stderr, "\nW[%2d] = %08X", t, W[ t ] );
	}
        fprintf( stderr, ".\n\n" );
        fprintf( stderr, "The hex values of A,B,C,D,E after pass t of the" );
        fprintf( stderr, " \"for t = 0 to 79\" loop (step\n(d) of" );
        fprintf( stderr, " Section 7 or step (c) of Section 8) are\n\n" );
        fprintf( stderr,
                 "\t    A          B          C          D          E\n" );
    }
#endif

    for ( t = 16; t < 80; t++ )
    {
	W[ t ] = S( 1, W[ t-3 ] ^ W[ t-8 ] ^ W[ t-14 ] ^ W[ t-16 ]);
    }

    for ( t = 0; t < 80; t++ )
    {
	TEMP = S( 5, A ) + F[ t ]( B, C, D ) + E + W[ t ] + K[ t ];
	E = D;
	D = C;
	C = S( 30, B );
	B = A;
	A = TEMP;
#if defined( VERBOSE )
	if ( sha1_verbose )
	{
	    fprintf( stderr, "\nt = %2d: %08X   %08X   %08X   %08X   %08X",
		     t, A, B, C, D, E );
	}
#endif
    }

#if defined( VERBOSE )
    if ( sha1_verbose )
    {
        fprintf( stderr, ".\n\nBlock %d has been processed.  ", sha1_block );
        fprintf( stderr, "The values of {Hi} are\n\n" );
        sha1_block++;
        fprintf( stderr, "H0 = %08X  +  %08X  =  %08X\n\n",
                 H[ 0 ], A, H[ 0 ] + A );
        fprintf( stderr, "H1 = %08X  +  %08X  =  %08X\n\n",
                 H[ 1 ], B, H[ 1 ] + B );
        fprintf( stderr, "H2 = %08X  +  %08X  =  %08X\n\n",
                 H[ 2 ], C, H[ 2 ] + C );
        fprintf( stderr, "H3 = %08X  +  %08X  =  %08X\n\n",
                 H[ 3 ], D, H[ 3 ] + D );
        fprintf( stderr, "H4 = %08X  +  %08X  =  %08X.\n\n",
                 H[ 4 ], E, H[ 4 ] + E );
    }

#endif

    H[ 0 ] += A;
    H[ 1 ] += B;
    H[ 2 ] += C;
    H[ 3 ] += D;
    H[ 4 ] += E;
}

void SHA1_update( SHA1_ctx* ctx, const void* pdata, word32 data_len )
{
    const byte* data = pdata;
    int use;
    int mlen;

    mlen = ctx->counter & SHA1_INPUT_MASK;
    ctx->counter += data_len;

/* deal with first block */

    use = min( SHA1_INPUT_BYTES - mlen, data_len );
    memcpy( ctx->M + mlen, data, use );
    mlen += use;
    data_len -= use;
    data += use;

    while ( mlen == SHA1_INPUT_BYTES )
    {
	make_big_endian32( ctx->M, SHA1_INPUT_WORDS );
	SHA1_transform( ctx->H, ctx->M );
	mlen = min( SHA1_INPUT_BYTES, data_len );
	memcpy( ctx->M, data, mlen );
	data_len -= mlen;
    }
}

/* Unlike most SHA1_final implementations semantics are defined if you
 * continue using this one after finalising.  You get the hash of the
 * substring.  The SHA1_final does not disrupt the state of the
 * context.
 */

void SHA1_final( SHA1_ctx* ctx, byte digest[ SHA1_DIGEST_BYTES ] )
{
  int mlen;
  int padding;
  word64 bits;
  byte* M = ctx->M;
  byte M2[ SHA1_INPUT_BYTES ];
  word32* H = (word32*) digest;

  mlen = ctx->counter % SHA1_INPUT_BYTES;

  M[ mlen ] = 0x80; mlen++; /* append a 1 bit */
  padding = SHA1_INPUT_BYTES - mlen;

  memcpy( H, ctx->H, SHA1_DIGEST_BYTES );

  if ( padding >= sizeof( word64 ) )
    {
      memset( M + mlen, 0x00, padding - sizeof( word64 ) );
    }
    else
      {
        memset( M + mlen, 0x00, SHA1_INPUT_BYTES - mlen );
        SHA1_transform( H, M );
        M = M2;
        memset(M, 0x00, SHA1_INPUT_BYTES - sizeof( word64 ) );
      }

  bits = htonq( ctx->counter * 8 );
  memcpy( M + SHA1_INPUT_BYTES - sizeof( word64 ), &bits, sizeof( word64 ) );
  SHA1_transform( H, M );
  make_big_endian32( H, SHA1_DIGEST_WORDS );
}
