*																				*
*		Routines to implement protocols, Diffie-Hellman, Massey-Omura and 		*
*	ElGamal for elliptic curve analogs.  Data transfer routines not included.	*
*																				*

#include "field2n.h"
#include "poly.h"
#include "eliptic.h"

/*  random seed is accessable to everyone, not best way, but functional.  */

unsigned long random_seed;
extern	FIELD2N poly_prime;

/*  below is from Mother code, till end of mother.  Above is all my fault.  */


static short mother1[10];
static short mother2[10];
static short mStart=1;

#define m16Long 65536L                          /* 2^16 */
#define m16Mask 0xFFFF          /* mask for lower 16 bits */
#define m15Mask 0x7FFF                  /* mask for lower 15 bits */
#define m31Mask 0x7FFFFFFF     /* mask for 31 bits */
#define m32Double  4294967295.0  /* 2^32-1 */

/* Mother **************************************************************
|       George Marsaglia's The mother of all random number generators
|               producing uniformly distributed pseudo random 32 bit values with
|               period about 2^250.
|       The arrays mother1 and mother2 store carry values in their
|               first element, and random 16 bit numbers in elements 1 to 8.
|               These random numbers are moved to elements 2 to 9 and a new
|               carry and number are generated and placed in elements 0 and 1.
|       The arrays mother1 and mother2 are filled with random 16 bit values
|               on first call of Mother by another generator.  mStart is the switch.
|       Returns:
|       A 32 bit random number is obtained by combining the output of the
|               two generators and returned in *pSeed.  It is also scaled by
|               2^32-1 and returned as a double between 0 and 1
|       SEED:
|       The inital value of *pSeed may be any long value
|       Bob Wheeler 8/8/94
|	removed double return since I don't need it.  mgr

void Mother(unsigned long *pSeed)
        unsigned long  number,
        short          n,
        unsigned short sNumber;

                /* Initialize motheri with 9 random values the first time */
        if (mStart) {
                sNumber= *pSeed&m16Mask;   /* The low 16 bits */
                number= *pSeed&m31Mask;   /* Only want 31 bits */

                for (n=18;n--;) {
				/* One line multiply-with-cary */
                        if (n==9)
                /* make cary 15 bits */

                /* Move elements 1 to 8 to 2 to 9 */

                /* Put the carry values in numberi */

                /* Form the linear combinations */



                /* Save the high bits of numberi as the new carry */
                /* Put the low bits of numberi into motheri[1] */

                /* Combine the two 16 bit random numbers into one 32 bit */

                /* Return a double value between 0 and 1 
        return ((double)*pSeed)/m32Double;  */

/*  Generate a random bit pattern which fits in a FIELD2N size variable.
	Calls Mother as many times as needed to create the value.

void random_field( value)
FIELD2N *value;
		Mother( &random_seed);
	 	value->e[i] = random_seed;
	value->e[0] &= UPRMASK;

/*  generate a random curve for a given field size.
	Enter with pointer to storage space for returned curve.
	Returns with curve.form = 0, curve.a2 = 0 and curve.a6
	as a random bit pattern.  This is for the equation
		y^2 + xy = x^3 + a_2x^2 + a_6

void rand_curve ( curv)
CURVE *curv;
	curv->form = 0;
	random_field( &curv->a6);
	null( &curv->a2);

/*  generate a random point on a given curve.
	Enter with pointer to curve and one pointer 
	to storage space for returned point.  Returns 
	one of solutions to above equation. Negate point
	to get other solution.

void rand_point( point, curve)
POINT	*point;
CURVE	*curve;
	FIELD2N	rf;

	random_field( &rf);
	poly_embed( &rf, curve, NUMWORD, rf.e[NUMWORD]&1, point);

/*  Compute a Diffie-Hellman key exchange.

	First routine computes senders public key.
	Enter with public point Base_point which sits on public curve E and
	senders private key my_private.
	Returns public key point My_public = my_private*Base_point to be sent 
	to other side.

void DH_gen_send_key( Base_point, E, my_private, My_public)
POINT *Base_point, *My_public;
FIELD2N *my_private;
	poly_elptic_mul( my_private, Base_point, My_public, E);

/*	Second routine computes shared secret that is same for sender and
	Enter with public point Base_point which sits on public curve E along with 
	senders public key their_public and receivers private key k.
	Returns shared_secret as x component of kP

void DH_key_share(Base_point, E, their_public, my_private, shared_secret)
POINT *Base_point, *their_public;
FIELD2N *my_private, *shared_secret;
	POINT	temp;
	poly_elptic_mul( my_private, their_public, &temp, E);
	copy (&temp.x, shared_secret);

/*  Send data to another person using ElGamal protocol. Send Hidden_data and
	Random_point to other side. */

void send_elgamal(
		Base_point, Base_curve, 
		Their_public, raw_data,
		 Hidden_data, Random_point)
FIELD2N *raw_data;
POINT	*Base_point, *Their_public, *Hidden_data, *Random_point;
CURVE	*Base_curve;
	FIELD2N	random_value;
	POINT	hidden_point, raw_point;
/*  create random point to help hide the data  */
	random_field (&random_value);
	poly_elptic_mul (&random_value, Base_point, Random_point, Base_curve);

/*  embed raw data onto the chosen curve,  Assume raw data is contained in
	least significant ELEMENTs of the field variable and we won't hurt anything
	using the most significant to operate on.  Uses the first root for y value.
	poly_embed( raw_data, Base_curve, 0, 0, &raw_point);

/*  Create the hiding value using the other person's public key  */

	poly_elptic_mul( &random_value, Their_publi