/*

Example GF(2^m) Elliptic Curve Diffie-Hellman program for very constrained environments. Uses point compression.
Stack-only memory allocation. 16-bit version. The Koblitz curve variant is ideal for wireless sensor networks.

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

#define MR_LITTLE_ENDIAN
#define MIRACL 16
#define mr_utype short
#define MR_IBITS 32
#define MR_LBITS 32
#define mr_unsign32 unsigned int
#define mr_dltype int
#define MR_DLTYPE_IS_INT
#define MR_STATIC 11
#define MR_ALWAYS_BINARY
#define MR_NOASM
#define MR_STRIPPED_DOWN
#define MR_GENERIC_MT
#define MAXBASE ((mr_small)1<<(MIRACL-1))
#define MR_BITSINCHAR 8
#define MR_SHORT_OF_MEMORY

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

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 mrecgf2m.c

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

lib /OUT:miracl.lib mrbits.obj mrio1.obj
lib /OUT:miracl.lib miracl.lib mrarth0.obj mrarth1.obj mrcore.obj 
lib /OUT:miracl.lib miracl.lib mrecgf2m.obj
del mr*.obj

rem Create the program

cl /O2 ecdh2m16.c miracl.lib

*/

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

#define CURVE_M 163
#define CURVE_A 7
#define CURVE_B 6
#define CURVE_C 3


/* NIST b163 elliptic curve Y^2+XY=X^3+A.X^2+B (from nist163.ecs). Irreducible polynomial 
   is x^163+x^7+x^6+x^3+1. Here is stored B, the group order q, and the generator G(x,y) */
/*
static const mr_small rom[]=
{0x05FD,0x4A32,0x7874,0x512F,0xEB10,0x1481,0x53CA,0xB8C9,0x1907,0x0A60,2,    
 0x4C33,0xA423,0x0C12,0x77E7,0x92FE,0x0002,0,0,0,0,4,   
 0x3E36,0xE834,0x4637,0xD499,0x1168,0xA099,0xD57E,0x86A2,0xA162,0xF0EB,3,     
 0x24F1,0x7973,0x5C0C,0xB11C,0xD545,0xA2CD,0x094F,0x71A0,0xBC6C,0xD51F,0};  
*/

/* NIST k163 Koblitz curve */
static const mr_small rom[]=
{
0x1,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0xA5EF,0x9958,0xCC0D,0x8AE0,0x2010,0x0,0x0,0x0,0x0,0x0,0x4,
0xA80F,0x109C,0xE90E,0x272D,0x911D,0x37CA,0x7A2B,0x5EF8,0x0B47,0x96C3,0x3,
0x6391,0xD6E7,0xA253,0x2923,0x142D,0xBABB,0x1DC3,0x8BB4,0x0E4C,0x947D,0x3};

#define WINDOW 4

/* 2^4 =16 precomputed points based on fixed generator G(x,y) */
/* (created using ebrick2.c program with window size of 4)    */

/* standard curve
static const mr_small prom[]=
{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x3e36,0xe834,0x4637,0xd499,0x1168,0xa099,0xd57e,0x86a2,0xa162,0xf0eb,0x3,
0x24f1,0x7973,0x5c0c,0xb11c,0xd545,0xa2cd,0x94f,0x71a0,0xbc6c,0xd51f,0x0,
0x9372,0x5fd,0xfdf2,0xaa17,0xe974,0x6648,0x5c03,0x31dd,0xf527,0x75f1,0x2,
0x90e0,0xdcf9,0x7c6a,0x7911,0xf662,0x5d2f,0xbdb2,0x9865,0x4960,0xb091,0x0,
0x87a6,0x78a8,0xfe58,0xe478,0x2364,0x3d3d,0xb263,0x3b85,0x885e,0x34c6,0x5,
0x3598,0xef27,0xe436,0xa6d7,0x1bd9,0x5300,0x731c,0x75cc,0x4f74,0xbf41,0x3,
0x5f08,0x4f68,0xaf88,0x6f8d,0x1b1f,0xd1c7,0x13ff,0x6f49,0x682a,0xbaa8,0x2,
0x1336,0xd530,0xdd1e,0xb4f6,0x423b,0x6454,0xaf45,0x4eb,0xe401,0x65c6,0x2,
0xc73d,0xa700,0x2a26,0x6f84,0xf5fd,0xe8f5,0x6da9,0x4db,0xdc95,0x48fc,0x6,
0x57cb,0x1db7,0x42ba,0xb5bf,0x25b4,0xabfd,0x5be3,0x466e,0x7012,0x2cf2,0x7,
0xd12e,0xeb7a,0x8e87,0x47e3,0x4ef1,0x5f9c,0x5483,0x2fcd,0x822e,0x3893,0x0,
0xbf09,0x7c98,0x9589,0xa41f,0xa2a3,0x680c,0x3842,0xdfa8,0x1659,0xedd4,0x1,
0x3d19,0xa346,0x4bb0,0xaf8c,0x658a,0x2288,0xc40d,0x84b3,0x449b,0x90cd,0x2,
0xbf11,0x6bb4,0x6afa,0x5e99,0xe97a,0x9b2a,0x1307,0xff21,0x8239,0xfbf5,0x5,
0xc649,0x4ab8,0x2ee,0x2fcf,0xfb85,0x3c7e,0x9ad9,0x76f0,0x45da,0xdbca,0x7,
0x93af,0xeeba,0xf276,0x59ad,0x3760,0xd25e,0xb2c1,0x3292,0x1b84,0x271d,0x4,
0x391c,0x37f9,0xfd60,0xf423,0x9624,0xbf07,0x36e0,0x4c90,0x5e19,0x6307,0x4,
0xdfb5,0xb726,0x49b3,0x38c3,0x88b7,0x6e09,0x4141,0x87b5,0xd73b,0xcb8,0x2,
0xdb88,0xd1ac,0x1fcc,0x64ca,0xfa73,0x690d,0x8b6f,0xc670,0x3919,0xb44b,0x2,
0x67d9,0x2b3f,0xcb1e,0xc01c,0xdcc8,0x5311,0xdd9a,0xdb9f,0x31e,0x9118,0x0,
0xd6e,0x9a5c,0x152f,0x4e99,0x3232,0xaf85,0xdccc,0x8db0,0x58d7,0xef0f,0x5,
0x3148,0x6db6,0x7e0a,0xefdd,0x9e67,0xcc81,0x79bc,0x56a9,0x69b4,0x8d11,0x3,
0xb917,0x8670,0xa2ac,0x3d61,0x588a,0x6ed8,0x4655,0x5cc9,0x413e,0x8096,0x2,
0x5f72,0xd871,0x6e6,0xc2ce,0x5c77,0xd50c,0xa69b,0x1553,0xfadc,0x8a20,0x2,
0x77b2,0x9dd0,0x8893,0xb297,0x17bb,0x7aa6,0xc172,0xadba,0xa9a2,0xf57d,0x1,
0xbbe2,0x6800,0xd74e,0x837a,0xcd95,0xdac7,0xc382,0x1082,0x4b2,0xb5ec,0x0,
0x5328,0x4383,0xd58b,0xa986,0x7c4e,0x8d7f,0x2a8d,0xfd64,0x62d4,0x6d44,0x3,
0x1e9,0xf199,0x3930,0x6099,0x8e9b,0x67c9,0xc90d,0x1ab9,0x4593,0x5d7f,0x6,
0x752,0x39e1,0x6730,0xde36,0xdb73,0xa867,0x53b5,0x5bcb,0x56c0,0x6b5e,0x3,
0xdcaa,0xaf59,0xf9ff,0x8bdb,0xc861,0x2221,0x5c1a,0x52b4,0x9b1f,0x221a,0x6};

*/

/* Koblitz curve */
static const mr_small prom[]=
{
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0xa80f,0x109c,0xe90e,0x272d,0x911d,0x37ca,0x7a2b,0x5ef8,0xb47,0x96c3,0x3,
0x6391,0xd6e7,0xa253,0x2923,0x142d,0xbabb,0x1dc3,0x8bb4,0xe4c,0x947d,0x3,
0x995f,0xc028,0xc193,0x2522,0xd939,0x5e65,0xa7b2,0xb529,0xbfa7,0xcf3b,0x3,
0x8b9b,0x15a9,0x596,0x8dc,0xf769,0xb43,0x9dbe,0xf449,0xd1b5,0x469e,0x3,
0x6d58,0x8430,0x716f,0x9e47,0xa1e1,0xb642,0xc627,0x42a3,0xc42d,0x3bc0,0x4,
0x22c5,0x4777,0x1328,0x7d37,0xccee,0xf2aa,0x48da,0xb649,0x1975,0x3258,0x4,
0xf8ec,0x9f6f,0x657a,0x5407,0x6dd,0x64b6,0xd3c4,0x2ed2,0xb3ce,0xb359,0x2,
0xc1bc,0xe161,0x2aaf,0xa168,0xe151,0xb399,0xe43e,0x50e2,0x3d25,0x36f5,0x2,
0x1b3d,0xe2e5,0x6c41,0xfcb6,0x9a93,0xb168,0xb6a5,0xdb00,0x8b24,0x8b07,0x6,
0x986d,0x487e,0xb259,0x6e67,0xd461,0xa44b,0xdbb8,0xc3a4,0x1cb9,0x2c36,0x5,
0x16a6,0x69cf,0x1b27,0x95d6,0xae2f,0xa0e9,0x6e40,0x8aa0,0x1992,0x7663,0x0,
0x5bb6,0xd3db,0xe73e,0x9ba7,0x2a49,0xedfb,0x54c8,0xbd03,0xaa14,0x5776,0x4,
0x6cea,0x7952,0x9495,0x17d0,0x9857,0xc8ab,0x28e9,0x9918,0xbd1b,0x7088,0x4,
0x84c8,0xca42,0xbcd9,0x86b,0x5933,0x2169,0x3751,0x69cf,0x8eb1,0x6614,0x0,
0x443c,0xbaf9,0xd850,0x5c37,0x8c1d,0x102,0xc5ae,0x48dc,0x8924,0xbdf7,0x7,
0xae90,0x64f0,0x1c0a,0x2b1d,0x39ae,0xe292,0x6898,0x385,0x5c3c,0x7ea9,0x5,
0xe7d5,0x13c1,0xd193,0xaf75,0x7253,0xa5b4,0xff4,0x8ba0,0x6942,0x8ba5,0x5,
0x2a8,0xd2e8,0x2bd2,0xc23e,0xb5a9,0xbdbf,0x9b7b,0xf181,0x68b7,0xb5fc,0x1,
0xf539,0xef19,0xca18,0xcaf,0x47bd,0x53a,0xc744,0x6158,0x86eb,0x8a62,0x1,
0x1827,0x8c84,0x237f,0x8533,0xf9ad,0xcb90,0xff83,0x3e5b,0x5350,0x34b0,0x2,
0x7391,0x8ea3,0xb6d3,0xa2c2,0x99b4,0xf3db,0x1a6b,0x8f68,0xb788,0xca6d,0x7,
0x107a,0x10e9,0xdde2,0xfc4c,0x338,0xf2d9,0xd6d8,0xf4cf,0xffe0,0x28b5,0x7,
0xee97,0x44d7,0x81c2,0xb22,0xdcfa,0xcfc9,0xcf8,0x9ad9,0x21d3,0xc84b,0x7,
0x1333,0x4bd5,0xe63d,0xb9a2,0x6fe,0x695a,0xc8d8,0x78ed,0xcba4,0x9b42,0x7,
0xfb03,0xb995,0xba77,0x8c0a,0xc44c,0x6503,0x3b5a,0xaac6,0x816d,0x5822,0x6,
0x3659,0xef07,0x6e3f,0xd368,0x597f,0xde09,0xb5dc,0x1c4c,0x322d,0x8080,0x7,
0x8101,0x22b0,0x40d8,0x8ffd,0xff52,0x96fa,0x9d69,0x8858,0x9fc2,0x187b,0x4,
0x5955,0xf979,0xad7b,0x805b,0x8673,0x8e4,0x4f73,0x891e,0xdac6,0x7c21,0x3,
0xd66d,0xd03c,0xc732,0x2b2,0xad5c,0x60b8,0x6b89,0x1ac2,0x99bc,0x18d3,0x3,
0x8b4,0xa252,0xe5d,0x543a,0xe178,0x81,0x439,0x5ead,0xf33b,0x1d22,0x4};

#define WORDS 11  /* Number of words per big variable 11*16 > 163 */

/* 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 *PA,*PB;
    big A,B,a,b,q,pa,pb,key,x,y;
    ebrick2 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*4,16); /* size of bigs is fixed */
    char mem_big[MR_BIG_RESERVE(10)];         /* we need 10 bigs... */
    char mem_ecp[MR_ECP_RESERVE(2)];          /* ..and two elliptic curve points */
 	memset(mem_big, 0, MR_BIG_RESERVE(10));   /* clear the memory */
	memset(mem_ecp, 0, MR_ECP_RESERVE(2));

    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);
    x=mirvar_mem(mip, mem_big, 5);
    y=mirvar_mem(mip, mem_big, 6);
    q=mirvar_mem(mip,mem_big,7);
    a=mirvar_mem(mip, mem_big, 8);
    b=mirvar_mem(mip, mem_big, 9);

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

    irand(mip, 3L);                      /* change parameter for different random numbers */
    promptr=0;
    init_big_from_rom(B,WORDS,rom,44,&promptr);  /* Read in curve parameter B from ROM */
                                                 /* don't need q or G(x,y) (we have precomputed table from it) */
    init_big_from_rom(q,WORDS,rom,44,&promptr);
    init_big_from_rom(x,WORDS,rom,44,&promptr);
    init_big_from_rom(y,WORDS,rom,44,&promptr);

    convert(mip,1,A);                            /* set A=1 */

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

    ebrick2_init(&binst,prom,A,B,CURVE_M,CURVE_A,CURVE_B,CURVE_C,WINDOW,CURVE_M);

/* offline calculations */

    bigbits(mip,CURVE_M,a);  /* A's random number */

    ia=mul2_brick(mip,&binst,a,pa,pa);    /* a*G =(pa,ya), ia is sign of ya */

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

/* online calculations */
    ecurve2_init(mip,CURVE_M,CURVE_A,CURVE_B,CURVE_C,A,B,FALSE,MR_PROJECTIVE);

    epoint2_set(mip,pb,pb,ib,PB); /* decompress PB */
    ecurve2_mult(mip,a,PB,PB);
    epoint2_get(mip,PB,key,key);

/* since internal base is HEX, can use otnum instead of cotnum - avoiding a base change */

printf("Alice's Key= ");
otnum(mip,key,stdout);

    epoint2_set(mip,pa,pa,ia,PB); /* decompress PA */
    ecurve2_mult(mip,b,PB,PB);
    epoint2_get(mip,PB,key,key);

printf("Bob's Key=   ");
otnum(mip,key,stdout);

/* clear the memory */

	memset(mem_big, 0, MR_BIG_RESERVE(10));
	memset(mem_ecp, 0, MR_ECP_RESERVE(2));

	return 0;
}
