/*
 * Cylink Corporation © 1998
 * 
 * This software is licensed by Cylink to the Internet Software Consortium to
 * promote implementation of royalty free public key cryptography within IETF
 * standards.  Cylink wishes to expressly thank the contributions of Dr.
 * Martin Hellman, Whitfield Diffie, Ralph Merkle and Stanford University for
 * their contributions to Internet Security.  In accordance with the terms of
 * this license, ISC is authorized to distribute and sublicense this software
 * for the practice of IETF standards.  
 *
 * The software includes BigNum, written by Colin Plumb and licensed by Philip
 * R. Zimmermann for royalty free use and distribution with Cylink's
 * software.  Use of BigNum as a stand alone product or component is
 * specifically prohibited.
 *
 * Disclaimer of All Warranties. THIS SOFTWARE IS BEING PROVIDED "AS IS",
 * WITHOUT ANY EXPRESSED OR IMPLIED WARRANTY OF ANY KIND WHATSOEVER. IN
 * PARTICULAR, WITHOUT LIMITATION ON THE GENERALITY OF THE FOREGOING, CYLINK
 * MAKES NO REPRESENTATION OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR
 * PURPOSE.
 *
 * Cylink or its representatives shall not be liable for tort, indirect,
 * special or consequential damages such as loss of profits or loss of
 * goodwill from the use or inability to use the software for any purpose or
 * for any reason whatsoever.
 *
 * EXPORT LAW: Export of the Foundations Suite may be subject to compliance
 * with the rules and regulations promulgated from time to time by the Bureau
 * of Export Administration, United States Department of Commerce, which
 * restrict the export and re-export of certain products and technical data.
 * If the export of the Foundations Suite is controlled under such rules and
 * regulations, then the Foundations Suite shall not be exported or
 * re-exported, directly or indirectly, (a) without all export or re-export
 * licenses and governmental approvals required by any applicable laws, or (b)
 * in violation of any applicable prohibition against the export or re-export
 * of any part of the Foundations Suite. All export licenses for software
 * containing the Foundations Suite are the sole responsibility of the licensee.
 */
 
/****************************************************************************
*  FILENAME: math.c   PRODUCT NAME: CRYPTOGRAPHIC TOOLKIT
*
*  FILE STATUS:
*
*  DESCRIPTION: Math Routines for the ToolKit 
*
*  PUBLIC FUNCTIONS:
*
*         int Sum_big (ord *X,
*                      ord *Y,
*                      ord *Z,
*                      u_int16_t len_X )
*
*         int Sub_big (ord *X,
*                      ord *Y,
*                      ord *Z,
*                      u_int16_t len_X )
*
*         void  Mul_big( ord *X, ord *Y,ord *XY,
*                        u_int16_t lx, u_int16_t ly)
*
*
*  PRIVATE FUNCTIONS:
*
*  REVISION  HISTORY:
*
*  14 Oct 94   GKL     Initial release
*  26 Oct 94   GKL     (alignment for big endian support )
*
****************************************************************************/

/****************************************************************************
*  INCLUDE FILES
****************************************************************************/
/* bn files */
#include "port_before.h"
#include "bn.h"
/* system files */
#ifdef VXD
#include <vtoolsc.h>
#else
#include <stdlib.h>
#include <string.h>
#endif
/* program files */
#include "cylink.h"
#include "ctk_endian.h"
#include "toolkit.h"
#include "port_after.h"

/****************************************************************************
*   NAME: void BigNumInit( void )
*
*
*  DESCRIPTION:  Initialize BigNum
*
*  INPUTS:
*     PARAMETERS:
*  OUTPUT:
*     PARAMETERS:
*
*     RETURN:
*
*
*  REVISION HISTORY:
*
*  29 Sep 96        Initial release
*
****************************************************************************/

void BigNumInit()
{
static int bignuminit = 0;
if(!bignuminit){
	bnInit();
	bignuminit = 1;
 }
}
/****************************************************************************
*   NAME: int Sum_big (ord *X,
*                      ord *Y,
*                      ord *Z,
*                      u_int16_t len_X )
*
*  DESCRIPTION:  Compute addition.
*
*  INPUTS:
*     PARAMETERS:
*           ord  *X        Pointer to first array
*           ord  *Y        Pointer to second array
*           int  len_X     Number of longs in X_l
*  OUTPUT:
*     PARAMETERS:
*           ord *Z         Pointer to result arrray
*
*     RETURN:
*            Carry bit
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*
****************************************************************************/

 int Sum_big (ord *X,
			  ord *Y,
			  ord *Z,
			  u_int16_t len_X )
{

struct BigNum src2,temp_bn;
ord *temp;
BigNumInit();

/*bnInit();
bnBegin(&src2);
bnBegin(&temp_bn);
*/
temp = (ord *) malloc((len_X*sizeof(ord)) + sizeof(ord));
temp_bn.size = len_X;
temp_bn.ptr = temp;
temp_bn.allocated = len_X + 1;

src2.ptr = Y;
src2.size = len_X;
src2.allocated = len_X;

memcpy(temp,X,len_X*sizeof(ord));
bnAdd(&temp_bn,&src2);
memcpy(Z,temp_bn.ptr,len_X*sizeof(ord));
/*bn package increments the size of dest by 1 if the carry bit is 1*/
free(temp);
if (temp_bn.size > len_X)
	return 1;
else
	return 0;
}

 int Sum (ord *X, ord *Y, u_int16_t len_X )
{

struct BigNum dest,src;
/*ord *temp;*/
BigNumInit();
#if 0
bnInit();
bnBegin(&src2);
bnBegin(&temp_bn);

temp = (ord *) malloc((len_X*sizeof(ord)) + sizeof(ord));
temp_bn.size = len_X;
temp_bn.ptr = temp;
temp_bn.allocated = len_X + 1;
#endif

dest.ptr = X;
dest.size = len_X-1;
dest.allocated = len_X;

src.ptr = Y;
src.size = len_X;
src.allocated = len_X;

/*memcpy(temp,X,len_X*sizeof(ord));*/
bnAdd(&dest,&src);
/*memcpy(Z,temp_bn.ptr,len_X*sizeof(ord));*/
/*bn package increments the size of dest by 1 if the carry bit is 1*/
/*free(temp);*/
if (dest.size > (u_int16_t)(len_X -1))
	return 1;
else
	return 0;
}


/****************************************************************************
*   NAME: int Sum_Q(ord *X,
*                      u_int16_t src,
*                      u_int16_t len_X )
*  DESCRIPTION:  Compute addition X += src.
*
*  INPUTS:
*     PARAMETERS:
*           ord  *X        Pointer to first array
*           u_int16_t  src    Second operand must be <65535
*           int  len_X     Number of ords in X_l
*  OUTPUT:
*     PARAMETERS:
*           ord *X         Pointer to result arrray
*
*     RETURN:
*            SUCCESS or -1
*
*  REVISION HISTORY:
*
*  21 Sep 96   AAB     Initial release
****************************************************************************/
 int Sum_Q(ord *X, u_int16_t src, u_int16_t len_X )
 {
  int status = SUCCESS;
  struct BigNum des;
  BigNumInit();
  /*bnInit();*/
  des.ptr = X;
  des.size = len_X;
  des.allocated = len_X;
  status = bnAddQ(&des, src);
  return status;
 }


/****************************************************************************
*  NAME:  int Sub_big (ord *X,
*                      ord *Y,
*                      ord *Z,
*                      u_int16_t len_X )
*
*
*  DESCRIPTION:  Compute subtraction.
*
*  INPUTS:
*     PARAMETERS:
*           ord   *X        Pointer to first array
*           ord   *Y        Pointer to second array
*           u_int16_t   len_X     Number of longs in X_l
*  OUTPUT:
*     PARAMETERS:
*           ord  *Z         Pointer to result arrray
*
*     RETURN:
*            Carry bit
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*
****************************************************************************/

int Sub_big  (ord *X,
			  ord *Y,
			  ord *Z,
			  u_int16_t len_X )
{
/* carry is not returned in bn version */
struct BigNum dest, src;
int status;
ord *temp;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
*/
src.ptr = Y;
src.size = len_X;
src.allocated = len_X;

temp = (ord*)malloc(len_X*sizeof(ord));
dest.ptr = temp;
dest.size = len_X;
dest.allocated = len_X;
memcpy(dest.ptr,X,len_X*sizeof(ord));

status = bnSub(&dest,&src);
memcpy(Z,dest.ptr,len_X*sizeof(ord));
free(temp);
return status;
}

#if 0
/****************************************************************************
*  NAME:   void  Mul_big( ord  *X, ord *Y, ord *XY,
*                         u_int16_t lx, u_int16_t ly)
*
*
*
*  DESCRIPTION:  Compute a product.
*
*  INPUTS:
*     PARAMETERS:
*            ord  *X                 Pointer to first long array
*            ord  *Y                 Pointer to second long array
*            u_int16_t lx               Leftmost non zero element of first array
*            u_int16_t ly               Leftmost non zero element of second array
*  OUTPUT:
*     PARAMETERS:
*            ord  *XY              Pointer to result
*
*     RETURN:
*
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*  08 Sep 95   AAB     Comment out calloc and discard the elements_in_X,
*                  elements_in_Y
****************************************************************************/
void  Mul_big( ord  *X, ord *Y, ord *XY,
						 u_int16_t lx, u_int16_t ly )
{
struct BigNum dest, src1, src2;
BigNumInit();
/*bnInit();*/
bnBegin(&dest);
/*
bnBegin(&src1);
bnBegin(&src2);
*/
src1.size = lx + 1;
src1.ptr = X;
src1.allocated = lx + 1;

src2.ptr = Y;
src2.size = ly + 1;
src2.allocated = ly + 1;

dest.ptr = XY;
dest.size = lx + ly + 2;
dest.allocated = lx + ly + 2;

/* Call bn routine */
bnMul(&dest, &src1,&src2);
}

#endif
/****************************************************************************
*  NAME:   void  Mul_big_1( ord  X, ord *Y, ord *XY,
*                                 u_int16_t lx, u_int16_t ly )
*
*
*
*  DESCRIPTION:  Compute a product.
*
*  INPUTS:
*     PARAMETERS:
*            ord  X                  Number
*            ord  *Y                 Pointer to long array
*            u_int16_t ly               Leftmost non zero element of second array
*  OUTPUT:
*     PARAMETERS:
*            ord  *XY              Pointer to result
*
*     RETURN:
*
*
*  REVISION HISTORY:
*
*  08 Oct 95   AAB     Initial relaese
*
****************************************************************************/
void  Mul_big_1( ord  X, ord *Y, ord *XY,
				u_int16_t ly )
{
struct BigNum dest, src;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
*/
src.ptr = Y;
src.size = ly + 1;
src.allocated = ly + 1;

dest.ptr = XY;
dest.size = ly + 2;
dest.allocated = ly + 2;

bnMulQ(&dest, &src, (unsigned)X);

}

/****************************************************************************
*  NAME: int Mul( u_int16_t X_bytes,
*                 ord        *X,
*                 u_int16_t Y_bytes,
*                 ord       *Y,
*                 u_int16_t P_bytes,
*                 ord   *P,
*                 ord   *Z )
*
*  DESCRIPTION:  Compute a modulo product
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X           Pointer to first operand
*            u_int16_t X_bytes     Number of bytes in X
*            ord   *Y           Pointer to second operand
*            u_int16_t Y_bytes     Number of bytes in Y
*            ord   *P           Pointer to modulo
*            u_int16_t P_bytes     Number of bytes in P
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z           Pointer to result
*
*      RETURN:
*          SUCCESS              No errors
*          ERR_INPUT_LEN        Invalid length for input data (zero bytes)
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*
****************************************************************************/

int Mul( u_int16_t X_bytes,
			ord *X,
		 u_int16_t Y_bytes,
			ord *Y,
		 u_int16_t P_bytes,
		 ord *P,
		 ord *Z )

{
	int status = SUCCESS;       /*function return status*/
	u_int16_t X_longs;             /*number of longs in X*/
	u_int16_t Y_longs;             /*number of longs in Y*/
	ord *XY;                    /*pointer to product (temporary)*/


struct BigNum dest, src1,src2, mod;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src1);
bnBegin(&src2);
bnBegin(&mod);
*/

src1.size = X_bytes/sizeof(ord);
src1.ptr = X;
src1.allocated = X_bytes/sizeof(ord);

src2.size = Y_bytes/sizeof(ord);
src2.ptr = Y;
src2.allocated =Y_bytes/sizeof(ord);

mod.size = P_bytes/sizeof(ord);
mod.ptr = P;
mod.allocated = P_bytes/sizeof(ord);

	 if ( P_bytes == 0 || X_bytes == 0 || Y_bytes == 0 )
	{
		 status = ERR_INPUT_LEN;
		return status;
	}
	if ( (X_bytes % sizeof(ord) != 0) ||
		  (Y_bytes % sizeof(ord) != 0) ||
		 (P_bytes % sizeof(ord) != 0) )
	{
		 status = ERR_INPUT_LEN;
		return status;
	}
	X_longs = (u_int16_t) (X_bytes / sizeof(ord));
	Y_longs = (u_int16_t) (Y_bytes / sizeof(ord));
	XY = (ord *)calloc( X_longs +  Y_longs, sizeof(ord) );
	if( !XY  )
	{
		return ERR_ALLOC;
	}
dest.size = X_longs + Y_longs;
dest.ptr = XY;
dest.allocated = X_longs + Y_longs;

bnMul (&dest,&src1,&src2);

status = bnMod(&dest, &dest, &mod);
memcpy(Z, dest.ptr, P_bytes);
free( XY );
	return status;
}

/****************************************************************************
*  NAME: int Square( u_int16_t X_bytes,
*                         ord    *X,
*                     u_int16_t P_bytes,
*                        ord    *P,
*                     ord   *Z )
*
*  DESCRIPTION:  Compute a modulo square
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X           Pointer to array to be squared
*            u_int16_t X_bytes     Number of bytes in X
*            ord   *P           Pointer to modulo
*            u_int16_t P_bytes     Number of bytes in P
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z           Pointer to result
*
*      RETURN:
*          SUCCESS              No errors
*          ERR_INPUT_LEN        Invalid length for input data (zero bytes)
*
*  REVISION HISTORY:
*
*  1  Sep 95   AAB     Initial release
****************************************************************************/

int Square( u_int16_t X_bytes,
				ord *X,
				u_int16_t P_bytes,
				ord *P,
				ord *Z )

{
	 int status = SUCCESS;       /*function return status*/

ord *XY;
struct BigNum dest, src, mod;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
bnBegin(&mod);
*/
	if ( P_bytes == 0 || X_bytes == 0 )
	{
		 status = ERR_INPUT_LEN;
		return status;
	 }
	if ( (X_bytes % sizeof(ord) != 0) ||
		  (P_bytes % sizeof(ord) != 0) )
	 {
		 status = ERR_INPUT_LEN;
		return status;
	 }
	XY = (ord *)malloc( 2*X_bytes );
	 if( !XY )
	 {
		 return ERR_ALLOC;
	 }

src.size = X_bytes/sizeof(ord);
src.ptr = X;
src.allocated = X_bytes/sizeof(ord);

dest.size = 2*X_bytes/sizeof(ord);
dest.ptr = XY;
dest.allocated = 2*X_bytes/sizeof(ord);

mod.size = P_bytes/sizeof(ord);
mod.ptr = P;
mod.allocated = P_bytes/sizeof(ord);

status = bnSquare(&dest, &src);
status = bnMod(&dest, &dest, &mod);
memcpy(Z, dest.ptr, P_bytes);
free(XY);
return status;
}


/****************************************************************************
*  NAME: int PartReduct( u_int16_t X_bytes,
*                        ord  *X,
*                        u_int16_t P_bytes,
*                        ord  *P,
*                        ord *Z )
*
*  DESCRIPTION:  Compute a modulo
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X              Pointer to array
*            u_int16_t X_bytes        Number of bytes in X
*            ord   *P              Pointer to modulo
*            u_int16_t P_bytes        Number of bytes in P
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z              Pointer to result
*
*      RETURN:
*          SUCCESS             No errors
*          ERR_INPUT_LEN       Invalid length for input data (zero bytes)
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*
****************************************************************************/

int PartReduct( u_int16_t X_bytes,
	  ord *X,
	  u_int16_t P_bytes,
	  ord   *P,
	  ord   *Z )
{
	 int status = SUCCESS;       /*function return status */


struct BigNum dest, /*src,*/ d;
ord *temp;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
bnBegin(&d);

src.size = X_bytes/sizeof(ord);
src.ptr = X;
src.allocated = X_bytes/sizeof(ord);
*/
d.size = P_bytes/sizeof(ord);
d.ptr = P;
d.allocated = P_bytes/sizeof(ord);

temp = (ord*)malloc(X_bytes);
dest.size = X_bytes/sizeof(ord);
dest.ptr = temp;
dest.allocated = X_bytes/sizeof(ord);
memcpy(dest.ptr, X, X_bytes);

status = bnMod(&dest, &dest, &d);

memcpy(Z, dest.ptr, P_bytes);
free(temp);

return status;

}

/****************************************************************************
*  NAME: int Expo( u_int16_t X_bytes,
*                  ord    *X,
*                  u_int16_t Y_bytes,
*                  ord    *Y,
*                  u_int16_t P_bytes,
*                  ord    *P,
*                  ord    *Z,
*                  YIELD_context *yield_cont )
*
*  DESCRIPTION:  Compute a modulo exponent
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X           Pointer to base array
*            u_int16_t X_bytes     Number of bytes in base
*            ord   *Y           Pointer to exponent array
*            u_int16_t Y_bytes     Number of bytes in exponent
*            ord   *P           Pointer to modulo
*            u_int16_t P_bytes     Number of bytes in  P
*            YIELD_context *yield_cont  Pointer to yield_cont structure (NULL if not used)
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z            Pointer to result
*
*  RETURN:
*          SUCCESS               No errors
*          ERR_INPUT_LEN         Invalid length for input data(zero bytes)
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*  08 Dec 94   GKL     Added YIELD_context
*  01 Sep 95           Fast exponentation algorithm
****************************************************************************/

int Expo( u_int16_t X_bytes, ord    *X,
		 u_int16_t Y_bytes, ord    *Y,
		 u_int16_t P_bytes, ord    *P,
		 ord   *Z )
{

int status = SUCCESS;     /*function return status*/

struct BigNum dest, n, exp, mod;
BigNumInit();
#if 0
/*bnInit();*/
bnBegin(&dest);
bnBegin(&n);
bnBegin(&exp);
bnBegin(&mod);
#endif

n.size = X_bytes/sizeof(ord);
n.ptr = X;
n.allocated = X_bytes/sizeof(ord);

exp.ptr = Y;
exp.size = Y_bytes/sizeof(ord);
exp.allocated = Y_bytes/sizeof(ord);

mod.ptr = P;
mod.size = P_bytes/sizeof(ord);
mod.allocated = P_bytes/sizeof(ord);

dest.ptr = Z;
dest.size = P_bytes/sizeof(ord);
dest.allocated = P_bytes/sizeof(ord);

/* Call bn routine */

status = bnExpMod(&dest, &n,
				  &exp, &mod);

return status;
}


/****************************************************************************
*  NAME: int DoubleExpo( u_int16_t X1_bytes,
*                  ord    *X1,
*                  u_int16_t Y1_bytes,
*                  ord    *Y1,
*  					 u_int16_t X2_bytes,
*                  ord    *X2,
*                  u_int16_t Y2_bytes,
*                  ord    *Y2,
*                  u_int16_t P_bytes,
*                  ord    *P,
*                  ord    *Z)
*
*  DESCRIPTION:  Compute a modulo exponent
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X1           Pointer to first base array
*            u_int16_t X1_bytes     Number of bytes in first base
*            ord   *Y1           Pointer to first exponent array
*            u_int16_t Y1_bytes     Number of bytes in first exponent
*            ord   *X2           Pointer to second base array
*            u_int16_t X2_bytes     Number of bytes in second base
*            ord   *Y2           Pointer to second exponent array
*            u_int16_t Y2_bytes     Number of bytes in second exponent            ord   *P           Pointer to modulo
*            ord   *P           Pointer to modulo
*            u_int16_t P_bytes     Number of bytes in
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z            Pointer to result
*
*  RETURN:
*          SUCCESS               No errors
*          ERR_INPUT_LEN         Invalid length for input data(zero bytes)
*
*  REVISION HISTORY:
*
*  21 Aug 96   AAB     Initial release
****************************************************************************/


int DoubleExpo( u_int16_t X1_bytes,ord    *X1,
					 u_int16_t Y1_bytes,ord    *Y1,
					 u_int16_t X2_bytes,ord    *X2,
					 u_int16_t Y2_bytes,ord    *Y2,
					 u_int16_t P_bytes,ord    *P,
										 ord    *Z)
{
int status = SUCCESS;     /*function return status*/
struct BigNum res, n1, e1, n2, e2, mod;
BigNumInit();

n1.size = X1_bytes/sizeof(ord);
n1.ptr = X1;
n1.allocated = X1_bytes/sizeof(ord);

e1.size = Y1_bytes/sizeof(ord);
e1.ptr = Y1;
e1.allocated = Y1_bytes/sizeof(ord);

n2.size = X2_bytes/sizeof(ord);
n2.ptr = X2;
n2.allocated = X2_bytes/sizeof(ord);

e2.size = Y2_bytes/sizeof(ord);
e2.ptr = Y2;
e2.allocated = Y2_bytes/sizeof(ord);

mod.ptr = P;
mod.size = P_bytes/sizeof(ord);
mod.allocated = P_bytes/sizeof(ord);

res.ptr = Z;
res.size = P_bytes/sizeof(ord);
res.allocated = P_bytes/sizeof(ord);
status = bnDoubleExpMod(&res, &n1, &e1, &n2, &e2, &mod);
return status;
}

/****************************************************************************
*  NAME: int Inverse( u_int16_t X_bytes,
*                     ord    *X,
*                     u_int16_t P_bytes,
*                     ord    *P,
*                     ord    *Z )
*
*
*
*
*  DESCRIPTION:  Compute a modulo inverse element
*
*  INPUTS:
*      PARAMETERS:
*            ord   *X           Pointer to array
*            u_int16_t X_bytes     Number of bytes in array
*            ord   *P           Pointer to modulo
*            u_int16_t P_bytes     Number of bytes in  P
*
*  OUTPUT:
*      PARAMETERS:
*            ord   *Z           Pointer to result
*
*      RETURN:
*          SUCCESS              No errors
*          ERR_INPUT_LEN        Invalid length for input data(zero bytes)
*          ERR_INPUT_VALUE  Invalid input value
*
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ     Initial release
*  14 Oct 94   GKL     Second version (big endian support)
*  08 Nov 94   GKL     Added input parameters check
*  01 Sep 95           Improve fuction
****************************************************************************/

int Inverse( u_int16_t X_bytes,
			  ord    *X,
			  u_int16_t P_bytes,
			 ord    *P,
				ord    *Z )
{
int status = SUCCESS;   /* function return status */

struct BigNum dest, src, mod;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
bnBegin(&mod);
*/
src.size = X_bytes/sizeof(ord);
src.ptr = X;
src.allocated = X_bytes/sizeof(ord);

mod.ptr = P;
mod.size = P_bytes/sizeof(ord);
mod.allocated = P_bytes/sizeof(ord);

dest.ptr = Z;
dest.size = (P_bytes/sizeof(ord))  ;
dest.allocated = (P_bytes/sizeof(ord)) + 1;
status = bnInv(&dest,&src,&mod);
return status;
}


/****************************************************************************
*  NAME:     void Add( ord    *X,
*                      ord    *Y,
*                      u_int16_t P_len,
*                      ord    *P,
*                      ord    *Z )

*
*  DESCRIPTION:  Compute modulo addition
*
*  INPUTS:
*          PARAMETERS:
*                         ord   *X              Pointer to first operand
*                         ord   *Y              Pointer to second operand
*                         u_int16_t P_len  Length of modulo
*                         ord   *P              Pointer to modulo
*  OUTPUT:
*             ord   *Z          Pointer to result
*          RETURN:
*
*  REVISION HISTORY:
*
*  24 sep 94    KPZ             Initial release
*  10 Oct 94    KPZ     Fixed bugs
*  14 Oct 94    GKL     Second version (big endian support)
*
****************************************************************************/
 /*
 int Add( ord *X,
		  ord *Y,
	  u_int16_t P_len,
		  ord *P,
			ord *Z )
{
	int status = SUCCESS;
	ord *temp;
	struct BigNum dest, src, mod;

bnInit();
bnBegin(&dest);
bnBegin(&src);
bnBegin(&mod);

temp = (ord*)malloc(P_len + sizeof(ord));
memcpy(temp, X, P_len);

dest.size = P_len/sizeof(ord);
dest.ptr = temp;
dest.allocated = P_len/sizeof(ord) + 1;

src.ptr = Y;
src.size = P_len/sizeof(ord);
src.allocated = P_len/sizeof(ord);

mod.ptr = P;
mod.size = P_len/sizeof(ord);
mod.allocated = P_len/sizeof(ord);

status = bnAdd(&dest,&src);
status = bnMod(&dest,&dest,&mod);
memcpy(Z,temp,P_len);
free(temp);
return status;
}
 */
 int Add( ord *X,
		  ord *Y,
	  u_int16_t P_len,
		  ord *P)
{
	int status = SUCCESS;
/*	ord *temp;*/
	struct BigNum dest, src, mod;

BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&src);
bnBegin(&mod);
*/
/*
temp = (ord*)malloc(P_len + sizeof(ord));
memcpy(temp, X, P_len);
*/
dest.size = P_len/sizeof(ord);
/*dest.ptr = temp;*/
dest.ptr = X;
dest.allocated = P_len/sizeof(ord) + 1;

src.ptr = Y;
src.size = P_len/sizeof(ord);
src.allocated = P_len/sizeof(ord);

mod.ptr = P;
mod.size = P_len/sizeof(ord);
mod.allocated = P_len/sizeof(ord);

status = bnAdd(&dest,&src);
status = bnMod(&dest,&dest,&mod);
/*
memcpy(Z,temp,P_len);
free(temp);
*/
return status;
}




/****************************************************************************
*  NAME:     int SteinGCD( ord *m,
*                          ord *b
*                          u_int16_t len )
*
*  DESCRIPTION:  Compute great common divisor
*
*  INPUTS:
*          PARAMETERS:
*           ord *m           Pointer to first number
*           ord *b           Pointer to second number
*           u_int16_t len       Number of elements in number
*  OUTPUT:
*
*  RETURN:
*           TRUE                   if gcd != 1
*           FALSE                                  if gcd == 1
*  REVISION HISTORY:
*
*
*  24 Sep 94    KPZ     Initial release
*  14 Oct 94    GKL     Second version (big endian support)
*  01 Sep 95    AAB     Speed up
*
****************************************************************************/


/* test if GCD equal 1 */
int  SteinGCD ( ord  *m,
		  ord  *n,
				u_int16_t len )
{

int status;
struct BigNum dest, a, b;
ord *temp;
BigNumInit();
/*bnInit();
bnBegin(&dest);
bnBegin(&a);
bnBegin(&b);
*/
a.size = len;
a.ptr = m;
a.allocated = len;

b.size = len;
b.ptr = n;
b.allocated = len;

temp = (ord*)malloc((len+1)*sizeof(ord));
dest.size = len;
dest.ptr = temp;
dest.allocated = len+1;

status = bnGcd(&dest, &a, &b);

if (*(ord *)(dest.ptr) == 0x01 && dest.size == 1)
 status = 0;
else
 status = 1;

free(temp);

return status;

}


/****************************************************************************
*  NAME: int DivRem( u_int16_t X_bytes,
*                    ord    *X,
*                    u_int16_t P_bytes,
*                    ord    *P,
*                    ord    *Z,
*                    ord    *D)
*
*  DESCRIPTION:  Compute a modulo and quotient
*
*  INPUTS:
*          PARAMETERS:
*                    ord   *X              Pointer to array
*                    u_int16_t X_bytes        Number of bytes in X
*                    ord   *P              Pointer to modulo
*                    u_int16_t P_bytes        Number of bytes in  P
*
*  OUTPUT:
*          PARAMETERS:
*            ord   *Z              Pointer to result
*            ord   *D                      Pointer to quotient
*          RETURN:
*                  SUCCESS             No errors
*          ERR_INPUT_LEN       Invalid length for input data (zero bytes)
*  REVISION HISTORY:
*
*  24 Sep 94   KPZ              Initial release
*  10 Oct 94   KPZ      Fixed bugs
*  14 Oct 94   GKL      Second version (big endian support)
*
****************************************************************************/

int DivRem( u_int16_t X_bytes,
		 ord    *X,
	  u_int16_t P_bytes,
		 ord    *P,
	  ord    *Z,
	  ord    *D)
{
	int status = SUCCESS;       /* function return status */

struct BigNum q, r, /*n,*/ d;
ord *temp;
BigNumInit();
/*bnInit();
bnBegin(&q);
bnBegin(&r);
bnBegin(&n);
bnBegin(&d);

n.size = X_bytes/sizeof(ord);
n.ptr = X;
n.allocated = X_bytes/sizeof(ord);
*/
d.size = P_bytes/sizeof(ord);
d.ptr = P;
d.allocated = P_bytes/sizeof(ord);

q.size = (X_bytes/sizeof(ord)) - (P_bytes/sizeof(ord)) + 1;
q.ptr = D;
q.allocated = (X_bytes/sizeof(ord)) - (P_bytes/sizeof(ord)) + 1;

temp = (ord *)malloc(X_bytes);
r.size = X_bytes/sizeof(ord);
r.ptr = temp;
r.allocated = X_bytes/sizeof(ord);
memcpy(r.ptr, X, X_bytes);

status = bnDivMod(&q, &r, &r, &d);

memcpy(Z, r.ptr, P_bytes);
free(temp);

return status;

}
