/*

Example Elliptic Curve Diffie-Hellman program for 32-bit constrained environments. Uses point compression.
Stack-only memory allocation

Use with this mirdef.h header (for a PC using MS C)

#define MR_LITTLE_ENDIAN
#define MIRACL 32
#define mr_utype int
#define MR_IBITS 32
#define MR_LBITS 32
#define mr_unsign32 unsigned int
#define mr_dltype __int64
#define mr_unsign64 unsigned __int64
#define MR_STATIC 6
#define MR_ALWAYS_BINARY
#define MR_STRIPPED_DOWN
#define MR_GENERIC_MT
#define MAXBASE ((mr_small)1<<(MIRACL-1))
#define MR_BITSINCHAR 8
#define MR_COMBA 6
#define MR_GENERALIZED_MERSENNE
#define MR_SPECIAL
#define MR_SIMPLE_BASE
#define MR_SIMPLE_IO

In an embedded environment perhaps these should be defined as well..

#define MR_NO_STANDARD_IO
#define MR_NO_FILE_IO

Build the library from these modules (Example using MS C compiler)

mex 6 ms86 mrcomba
rem (mex 6 sse2 mrcomba) will be faster on most PCs that support SSE2 
cl /c /O2 /W3 mrcore.c
cl /c /O2 /W3 mrarth0.c
cl /c /O2 /W3 mrarth1.c
cl /c /O2 /W3 mrio1.c
cl /c /O2 /W3 mrbits.c
cl /c /O2 /W3 mrcurve.c
cl /c /O2 /W3 mrsroot.c
cl /c /O2 /W3 mrjack.c
cl /c /O2 /W3 mrlucas.c
cl /c /O2 /W3 mrarth2.c
cl /c /O2 /W3 mrmonty.c
cl /c /O2 /W3 mrcomba.c
cl /c /O2 /W3 mrxgcd.c
cl /c /O2 /W3 mrmuldv.c
cl /c /O2 /W3 mrebrick.c

rem
rem Create library 'miracl.lib'
del miracl.lib

lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.obj mrmuldv.obj
lib /OUT:miracl.lib miracl.lib mrbits.obj mrarth2.obj mrlucas.obj mrjack.obj
lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj mrebrick.obj
lib /OUT:miracl.lib miracl.lib mrcurve.obj mrsroot.obj
del mr*.obj

rem Create the program

cl /O2 ecdhp.c miracl.lib

*/

#include <stdio.h>
#include <string.h>
#include "miracl.h"

/* !!!!!! THIS CODE AND THESE ROMS ARE NOW CREATED AUTOMATICALLY USING THE ROMAKER.C APPLICATION !!!!!!!! */
/* !!!!!! READ COMMENTS IN ROMAKER.C !!!!!! */

#define HEXDIGS (MIRACL/4)
#define CURVE_BITS 192

/* NIST p192 bit elliptic curve Y^2=X^3-3X+B (from secp192.ecs). 
   Here is stored P, B, the group order q, and the generator G(x,y) */

static const mr_small rom[]=
{0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFE,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0xC146B9B1,0xFEB8DEEC,0x72243049,0x0FA7E9AB,0xE59C80E7,0x64210519,
0xB4D22831,0x146BC9B1,0x99DEF836,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,
0x82FF1012,0xF4FF0AFD,0x43A18800,0x7CBF20EB,0xB03090F6,0x188DA80E,
0x1E794811,0x73F977A1,0x6B24CDD5,0x631011ED,0xFFC8DA78,0x07192B95};

#define WINDOW 4

/* 32 precomputed points based on fixed generator G(x,y)        */
/* (created using romaker.c program with window size of 4)      */

/* These values are only correct if MR_SPECIAL is defined!      */

static const mr_small prom[]=
{0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,
0x82ff1012,0xf4ff0afd,0x43a18800,0x7cbf20eb,0xb03090f6,0x188da80e,
0x1e794811,0x73f977a1,0x6b24cdd5,0x631011ed,0xffc8da78,0x7192b95,
0x5d7c48d8,0xc39649c5,0x5a927c35,0xeb2cdfae,0xcba671fb,0x67e30cbd,
0xecbfbe7d,0x7a83cee1,0x6301577,0xce32d03c,0x5810f5c3,0xa93549c4,
0x66e3ead3,0x6f5ef889,0xdfc9bf1a,0xf29e6fea,0x452006e0,0xce216bb8,
0x927b3779,0x46b9092d,0xb5b80a20,0x1d0aeb4b,0x5aaec958,0xd98a2ee2,
0xc0a1e340,0xb19963d8,0x80d1090b,0x4730d4f4,0x184ac737,0x51a581d9,
0xe69912a5,0xecc56731,0x2f683f16,0x7cdfcea0,0xe0bb9f6e,0x5bd81ee2,
0xd4f43374,0xe4b15a2d,0xf292c341,0x757eea7,0xd0f8dc24,0xc730691,
0xbbf45e00,0xdf797890,0xe9de8708,0x8a9e83,0x9354de3e,0x31b24c31,
0xddf63aba,0xcb5ec043,0xf84f41e1,0xc94c21d9,0x61d24416,0xf0f40883,
0x406495f7,0xf37585b0,0x16bcd0ca,0xe5de3b5b,0xe13ea488,0x27853c1a,
0x8e8ae68f,0xd074232a,0xee29f7a9,0x749e528e,0x9716469f,0x611dea3,
0xd8043cc,0x66b867dd,0x3a727de6,0x6a654654,0x8338bdc9,0xf9546052,
0xc5d8f50,0xb6eb7193,0xb904b596,0x1c245c02,0x951f7513,0x4bc1f71,
0xbe34803d,0xa4d0916e,0x8c21962a,0x8bec948a,0xfd69f8d0,0x150096e7,
0xe71aac0c,0xbd44ffe8,0x4322d065,0x7d69a0b0,0xeca3ba2a,0x9f56d96c,
0x25a59dce,0xee59f0d1,0xc3f4575a,0x837d62dd,0x35de73d9,0xa4e07fb3,
0x1cf46ae2,0xec76760c,0xa33d44b0,0xff549832,0xf3185c11,0xe95ad210,
0x38ed372e,0x273e5ec5,0xb0ab1169,0x51d39136,0x8f3a27c8,0xa5ea86f6,
0x74d2d7d5,0x291237ea,0x56338e9b,0x953636ee,0x285c120c,0xda65e86,
0xf13c3233,0x1302f04c,0x978391b2,0xfc898ab9,0x3aa06272,0x26d65c2e,
0x18c5efe6,0xd50947a8,0xfe113c6c,0x45db23ae,0xe5bbe86d,0x91f199f2,
0x60fec064,0x376881b6,0x475daea4,0x387343e9,0xac8d8a19,0xeccd57e8,
0x5b510228,0xc9fef5b9,0x192ebcd6,0x374c0a4c,0xce6a83f9,0x2298f204,
0xf4c574d0,0x46e4b820,0xefeb2cc0,0x6d58644,0x10c3c949,0xe713a400,
0x2d64eedf,0x6178cb0e,0xb85e1f99,0x27af7d5e,0x6cb7be1f,0xd873ced7,
0x52a67f9c,0xefc9129c,0x6004d9ad,0xa3d7b957,0xdc41f8e2,0xfc599808,
0x7fdf928a,0xbb6c6b59,0xd7f93bf4,0xad167ef0,0x154e061c,0xfaa9e432,
0xd52c8f3f,0xc3d0d63,0xd5f7e08f,0x6101b2be,0xd6ae3cf3,0xd877cddd};


#define WORDS 6  /* Number of words per big variable 6*32 = 192 */

/* Note that in a real application a source of real random numbers would be required, to
   replace those generated by MIRACL's internal pseudo-random generator "bigbits"  
   Alternatively from a truly random and unguessable seed, use MIRACL's strong random 
   number generator */

/* Elliptic Curve Diffie-Hellman, using point compression to minimize bandwidth, 
   and precomputation to speed up off-line calculation */

int main()
{
    int ia,ib,promptr;
    epoint *PB;
    big A,B,p,a,b,pa,pb,key;
    ebrick binst;
    miracl instance;      /* create miracl workspace on the stack */

/* Specify base 16 here so that HEX can be read in directly without a base-change */

    miracl *mip=mirsys(&instance,WORDS*HEXDIGS,16); /* size of bigs is fixed */
    char mem_big[MR_BIG_RESERVE(8)];          /* we need 8 bigs... */
    char mem_ecp[MR_ECP_RESERVE(1)];          /* ..and 1 elliptic curve points */
 	memset(mem_big, 0, MR_BIG_RESERVE(8));    /* clear the memory */
	memset(mem_ecp, 0, MR_ECP_RESERVE(1));

    A=mirvar_mem(mip, mem_big, 0);       /* Initialise big numbers */
    B=mirvar_mem(mip, mem_big, 1);
    pa=mirvar_mem(mip, mem_big, 2);
    pb=mirvar_mem(mip, mem_big, 3);
    key=mirvar_mem(mip, mem_big, 4);
    a=mirvar_mem(mip, mem_big, 5);
    b=mirvar_mem(mip, mem_big, 6);
    p=mirvar_mem(mip, mem_big, 7);

    PB=epoint_init_mem(mip, mem_ecp, 0); /* initialise Elliptic Curve points */

    irand(mip, 3L);                      /* change parameter for different random numbers */

    promptr=0;
    init_big_from_rom(p,WORDS,rom,WORDS*5,&promptr);  /* Read in prime modulus p from ROM   */
    init_big_from_rom(B,WORDS,rom,WORDS*5,&promptr);  /* Read in curve parameter B from ROM */
                                                 /* don't need q or G(x,y) (we have precomputed table from it) */

    convert(mip,-3,A);                           /* set A=-3 */

/* Create precomputation instance from precomputed table in ROM */

    ebrick_init(&binst,prom,A,B,p,WINDOW,CURVE_BITS);

/* offline calculations */

    bigbits(mip,CURVE_BITS,a);  /* A's random number */
    ia=mul_brick(mip,&binst,a,pa,pa);    /* a*G =(pa,ya), ia is sign of ya */

    bigbits(mip,CURVE_BITS,b);  /* B's random number */
    ib=mul_brick(mip,&binst,b,pb,pb);    /* b*G =(pb,yb), ib is sign of yb */

/* online calculations */
    ecurve_init(mip,A,B,p,MR_PROJECTIVE);
    epoint_set(mip,pb,pb,ib,PB); /* decompress PB */
    ecurve_mult(mip,a,PB,PB);
    epoint_get(mip,PB,key,key);

/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */
#ifndef MR_NO_STANDARD_IO
printf("Alice's Key= ");
otnum(mip,key,stdout);
#endif

    epoint_set(mip,pa,pa,ia,PB); /* decompress PA */
    ecurve_mult(mip,b,PB,PB);
    epoint_get(mip,PB,key,key);

#ifndef MR_NO_STANDARD_IO
printf("Bob's Key=   ");
otnum(mip,key,stdout);
#endif

/* clear the memory */

	memset(mem_big, 0, MR_BIG_RESERVE(8));
	memset(mem_ecp, 0, MR_ECP_RESERVE(1));

	return 0;
}
