/****************************************************************************/
/*	Copyright (c) 2009, Bendor Research Pty. Ltd. All rights reserved.		*/
/*	This software is released under the GNU General Public License, version */
/*	3, with the exemptions that 1) the header files installed by this		*/
/*	package can be included in closed-source code and 2) the libraries		*/
/*	built by this package can be statically linked into a closed-source		*/
/*	binary. See the file LICENSE for the details.							*/
/*	This software is provided "AS IS", without any warranty or guarantee.	*/
/*	By using this software you acknowledge that neither Bendor Research nor */
/*	any of its personnel or affiliates can be held liable for any damages,	*/
/*	including, but not limited to, loss of business, loss of money, loss of */
/*	life, loss or reputation, arising out of this software being faulty or	*/
/*	not performing as advertised, even if Bendor Research was aware of such */
/*	faults in the software. You use this software at your own risk, any and */
/*	all liabilities that arise out of your using this software are strictly */
/*	yours.																	*/
/****************************************************************************/

#include <string.h>
#include "crypto.h"

/****************************************************************************/
/*						Macros used by SHA1									*/
/****************************************************************************/

/*
*	Initialisation constants
*/

#define H0			0x67452301
#define H1			0xefcdab89
#define H2			0x98badcfe
#define H3			0x10325476
#define H4			0xc3d2e1f0

/*
*	Transformation constants
*/

#define K0			0x5a827999
#define K1			0x5a827999
#define K2			0x6ed9eba1
#define K3			0x8f1bbcdc
#define K4			0xca62c1d6

/*
*	Core transformation functions
*/

#define F0(b,c,d)	(((b)&(c))|(~(b)&(d)))
#define F1(b,c,d)	(((b)&(c))|(~(b)&(d)))
#define F2(b,c,d)	((b)^(c)^(d))
#define F3(b,c,d)	(((b)&(c))|((b)&(d))|((c)&(d)))
#define F4(b,c,d)	((b)^(c)^(d))

/*
*	Add two number modulo 16
*/

#define M(a,b)		(((a)+(b))&15)

/*
*	Rotate an unsigned number to the left by a given amount.
*	It can handle any number of rotations, including 0 and numbers
*	that are larger than 31.
*/

#define R(x,y)		(((y)&31)?(((x)<<((y)&31))|((x)>>(32-((y)&31)))):(x))

/*
*	Data manipulation core functions
*/

#define B0(x,n)		(x[n&15])
#define B1(x,n)		(x[n&15]=R(x[M(n,13)]^x[M(n,8)]^x[M(n,2)]^x[M(n,0)],1))

/*
*	Transformation procedures. The parameter 'e' and 'b' must be lvalues
*	because they are modified by these procedures.
*/

#define Q0(a,b,c,d,e,x,n) do{e+=F0(b,c,d)+B0(x,n)+K0+R(a,5);b=R(b,30);}while(0)
#define Q1(a,b,c,d,e,x,n) do{e+=F1(b,c,d)+B1(x,n)+K1+R(a,5);b=R(b,30);}while(0)
#define Q2(a,b,c,d,e,x,n) do{e+=F2(b,c,d)+B1(x,n)+K2+R(a,5);b=R(b,30);}while(0)
#define Q3(a,b,c,d,e,x,n) do{e+=F3(b,c,d)+B1(x,n)+K3+R(a,5);b=R(b,30);}while(0)
#define Q4(a,b,c,d,e,x,n) do{e+=F4(b,c,d)+B1(x,n)+K4+R(a,5);b=R(b,30);}while(0)

/****************************************************************************/
/*						Local prototypes									*/
/****************************************************************************/

static	void	BC_Sha1Start( unsigned *s );
static	void	BC_Sha1Block( unsigned *s, unsigned *p );

/****************************************************************************/
/*						Public data											*/
/****************************************************************************/

/*
*	SHA1 function and size table
*/

const struct bc_hfun_s _bc_hash_sha1 = {

	BC_Sha1Start,
	BC_Sha1Block,
	20, 0
};

/****************************************************************************/
/*						Local functions										*/
/****************************************************************************/

/*
*	Initialise the hash structure for SHA1 usage
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

static	void	BC_Sha1Start( unsigned *s )
{
	s[ 0 ] = H0;
	s[ 1 ] = H1;
	s[ 2 ] = H2;
	s[ 3 ] = H3;
	s[ 4 ] = H4;
}

/*
*	Processes the next 64 bytes of input for SHA1 hash
*	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/

static	void	BC_Sha1Block( unsigned *s, unsigned *p )
{
unsigned int	a, b, c, d, e;
unsigned int	i, t;

	a = s[ 0 ];
	b = s[ 1 ];
	c = s[ 2 ];
	d = s[ 3 ];
	e = s[ 4 ];

	for ( i = 0 ; i < 16 ; i++ ) {

		Q0( a, b, c, d, e, p, i );
		t = a; a = e; e = d; d = c; c = b; b = t;
	}

	for ( ; i < 20 ; i++ ) {

		Q1( a, b, c, d, e, p, i );
		t = a; a = e; e = d; d = c; c = b; b = t;
	}

	for ( ; i < 40 ; i++ ) {

		Q2( a, b, c, d, e, p, i );
		t = a; a = e; e = d; d = c; c = b; b = t;
	}

	for ( ; i < 60 ; i++ ) {

		Q3( a, b, c, d, e, p, i );
		t = a; a = e; e = d; d = c; c = b; b = t;
	}

	for ( ; i < 80 ; i++ ) {

		Q4( a, b, c, d, e, p, i );
		t = a; a = e; e = d; d = c; c = b; b = t;
	}

	s[ 0 ] += a;
	s[ 1 ] += b;
	s[ 2 ] += c;
	s[ 3 ] += d;
	s[ 4 ] += e;
}

