/*

Example Elliptic Curve Diffie-Hellman program for 8-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 8
#define mr_utype char
#define MR_IBITS 32
#define MR_LBITS 32
#define mr_unsign32 unsigned int
#define mr_dltype short
#define MR_STATIC 20
#define MR_ALWAYS_BINARY
#define MR_NOASM
#define MR_STRIPPED_DOWN
#define MR_GENERIC_MT
#define MAXBASE ((mr_small)1<<(MIRACL-1))
#define MR_COMBA 20
#define MR_SPECIAL
#define MR_PSEUDO_MERSENNE
#define MR_BITSINCHAR 8
#define MR_SMALL_EWINDOW
#define MR_NO_ECC_MULTIADD
#define MR_NO_LAZY_REDUCTION
#define MR_SIMPLE_BASE
#define MR_SIMPLE_IO

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

mex 20 c mrcomba
rem In a real 8-bit setting, a suitable assembly language .mcs file would be used. Here we use C.
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 mrebrick.c

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

lib /OUT:miracl.lib mrio1.obj mrmonty.obj mrcomba.obj mrxgcd.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 ecdhp8.c miracl.lib

For Atmel AVR (atmega128) use

#define MR_LITTLE_ENDIAN
#define MIRACL 8
#define mr_utype char
#define MR_IBITS 16  
#define MR_LBITS 32
#define mr_unsign32 unsigned long
#define mr_dltype int 
#define mr_qltype long
#define MR_STATIC 20
#define MR_ALWAYS_BINARY
#define MR_STRIPPED_DOWN
#define MR_GENERIC_MT
#define MAXBASE ((mr_small)1<<(MIRACL-1))
#define MR_COMBA 20
#define MR_SPECIAL
#define MR_PSEUDO_MERSENNE
#define MR_NOASM
#define MR_BITSINCHAR 8
#define MR_NO_STANDARD_IO
#define MR_NO_FILE_IO
#define MR_NO_LAZY_REDUCTION
#define MR_NO_ECC_MULTIADD
#define MR_SIMPLE_BASE
#define MR_SIMPLE_IO
#define MR_SMALL_EWINDOW
#define MR_AVR

Note this last line is added manually - it will not be added by config

and execute

mex 20 avr4 mrcomba

Note that reading data from program memory (NVM) is a little complex on the AVR!

*/

#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 160

/* Pseudo Mersenne 160 bit elliptic curve Y^2=X^3-3X+383 modulo 2^160-57
   Here is stored P, B, the group order q, and the generator G(x,y)       */


#ifdef MR_AVR
__attribute__((__progmem__))
#endif 

static const mr_small rom[]=
{
0xC7,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0x7F,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x25,0x32,0x7F,0x71,0x4B,0x4F,0xA0,0x01,0x3F,0x0E,0xFF,0xFF,0xFF,0xFF,0xFE,0xFF,0xFF,0xFF,0xFF,0xFF,   
0xf1,0x66,0x56,0xb7,0xee,0xbf,0x27,0xd0,0x4a,0xd0,0xb7,0x9,0x20,0x4e,0x59,0xed,0x5e,0xdc,0x8a,0xa,
0xda,0xc9,0x45,0x55,0xcc,0x6c,0x1c,0x11,0x9f,0x38,0x4d,0xac,0xd3,0x43,0x76,0xaf,0x5c,0x2d,0xfb,0x20};

#define WINDOW 4

/* 16 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!      */

#ifdef MR_AVR
__attribute__((__progmem__))
#endif 
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,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,
0xf1,0x66,0x56,0xb7,0xee,0xbf,0x27,0xd0,0x4a,0xd0,0xb7,0x9,0x20,0x4e,0x59,0xed,0x5e,0xdc,0x8a,0xa,
0xda,0xc9,0x45,0x55,0xcc,0x6c,0x1c,0x11,0x9f,0x38,0x4d,0xac,0xd3,0x43,0x76,0xaf,0x5c,0x2d,0xfb,0x20,
0xa,0xf8,0xdc,0xe5,0x96,0x7b,0xa2,0xad,0x89,0xa7,0xf2,0x19,0xfe,0xd6,0xcb,0xa0,0x91,0x44,0xaf,0xc6,
0x35,0xee,0xc1,0xa4,0x76,0xbe,0xda,0x91,0x5c,0xa3,0x6f,0xd9,0x24,0xe8,0x41,0x4f,0xe7,0x0,0xa,0x67,
0x16,0x9d,0xb1,0x30,0x2d,0xfa,0x9a,0x47,0x30,0x39,0x82,0xbb,0x39,0x7e,0x78,0x9e,0x1d,0xc9,0xa5,0x31,
0x64,0xe3,0x3,0x9b,0x4f,0xde,0x51,0x3f,0xb5,0x2,0x9f,0x68,0xe,0x65,0x3a,0x2f,0xae,0x4a,0xe9,0x79,
0xbf,0x66,0x86,0x3f,0xa0,0x5d,0x7f,0xc7,0x55,0x27,0x85,0x75,0xaa,0x9f,0x58,0x97,0x1f,0xec,0xe6,0xab,
0x92,0x36,0x32,0xf7,0x73,0x20,0x9d,0xdf,0x78,0x84,0x29,0x6d,0x3f,0x45,0x92,0xe7,0xd0,0x2d,0x64,0x2e,
0x62,0xd4,0x5d,0x1,0xe0,0x73,0x26,0xca,0xaa,0xcb,0xe7,0x87,0xf5,0xdd,0xa4,0xfe,0xd1,0xc7,0xbf,0xc7,
0x75,0x18,0x47,0xea,0x19,0xcb,0x4,0xd9,0x99,0x4f,0xc5,0x8b,0x57,0xf6,0xc0,0xe,0x11,0xaf,0x99,0x84,
0xdc,0x3b,0x49,0x31,0xb,0x77,0x55,0xdc,0x97,0xaa,0x56,0x7c,0x35,0x70,0x27,0x2c,0xd7,0xb5,0xee,0xc8,
0x4d,0x17,0x43,0xfe,0x80,0x8f,0x47,0x30,0xc2,0x83,0x91,0x94,0x17,0x65,0xa,0xfd,0x28,0xa5,0x4a,0x32,
0xb2,0x76,0xef,0xb8,0x49,0xdb,0xa,0xb0,0xb6,0x1a,0x5f,0xef,0x47,0x62,0x9f,0x37,0x7f,0xc,0xc,0x98,
0xe1,0x34,0x68,0x6b,0x46,0xe1,0x7,0x6c,0x4f,0x82,0xba,0x5d,0xf9,0xea,0xeb,0x69,0xa9,0xc2,0xa,0xa,
0x9e,0x9c,0xda,0xb0,0xfa,0xec,0x83,0xd1,0x38,0xc7,0x51,0x78,0x9d,0xe6,0xd4,0x5,0x83,0xde,0x56,0x1e,
0xf9,0x58,0xce,0x14,0x79,0xc7,0x63,0xa5,0x9b,0x10,0xf5,0x31,0x26,0x9c,0x1c,0x8b,0xba,0x7b,0x2b,0xcc,
0xdc,0x70,0xf7,0xc7,0xb5,0x3a,0xf0,0xc8,0x7d,0x5f,0x27,0xc1,0x4f,0x7b,0x26,0x84,0x8d,0xc4,0x88,0x9d,
0x7d,0x91,0xee,0x3e,0x20,0xc8,0xaf,0x22,0x5,0x47,0x58,0x4c,0x83,0xc6,0xae,0x76,0x6e,0x43,0x4b,0xd4,
0x54,0xf8,0xdf,0xa2,0xb9,0x4f,0xf5,0x83,0xfd,0x8e,0xbd,0xd7,0xf8,0xf0,0x4a,0xac,0xfa,0x13,0xa7,0xd0,
0xf3,0x25,0x61,0x4f,0x6b,0xec,0x13,0xdf,0xe1,0x4d,0x35,0x7e,0xba,0xf4,0xd9,0xa3,0xc,0x6e,0x82,0xb2,
0xf9,0xf4,0xf1,0x6d,0xce,0x72,0x63,0x7c,0x81,0x4b,0xaf,0x42,0xd8,0x85,0xa9,0xab,0xea,0xc9,0x1d,0x53,
0xb2,0xce,0xf9,0xd5,0x41,0x72,0xc8,0x5a,0x8f,0xc,0x75,0xbc,0xa9,0xf7,0x93,0xe5,0x6e,0xbe,0x76,0xd2,
0x6f,0x54,0xc9,0x15,0x86,0x48,0xe6,0x99,0xdc,0xcc,0x75,0x1a,0xfd,0xd6,0xd0,0x8c,0xcd,0x8,0xa7,0x39,
0xd0,0x64,0x2d,0xc,0xf3,0xa2,0xda,0x5d,0x96,0x76,0xf4,0x31,0x86,0xa,0x74,0xe7,0x6,0x60,0x29,0xb2,
0xbb,0xde,0x8,0x56,0x9f,0x8b,0x3f,0xff,0x30,0x4b,0xdc,0x32,0x4c,0x8f,0xb,0x63,0xd5,0x47,0x3f,0xb,
0xda,0x1c,0x77,0x84,0x5b,0x9d,0xaa,0x2f,0x77,0x6f,0xe8,0x1d,0x4e,0x69,0x6,0x8f,0x3d,0x7c,0xaf,0x7,
0xa1,0x42,0xae,0x2,0x24,0xa3,0x53,0x31,0x1f,0xe6,0x43,0x56,0x21,0x70,0x6e,0x1f,0x32,0xb3,0x17,0xe4,
0x51,0x4a,0xc0,0xd1,0xd1,0xb7,0xee,0xd6,0xc6,0xa8,0x3b,0x9a,0xe2,0xb8,0x11,0x8c,0x0,0xae,0x9b,0xdf,
0x3,0xbc,0x2c,0x78,0x5f,0xcf,0x24,0xba,0x7f,0x60,0x9,0x4c,0x8c,0x86,0xdd,0x11,0xfe,0x3f,0xe1,0xf5,
0xa0,0xb0,0x30,0xb6,0xb7,0x80,0xd8,0xb4,0x6a,0xbc,0x2e,0x43,0xaa,0x3b,0x4,0x28,0x13,0xef,0xa1,0x47};

#define WORDS 20  /* Number of words per big variable 20*8 = 160 */

/* 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,p,a,b,pa,pb,key,x,y;
    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(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);
    a=mirvar_mem(mip, mem_big, 7);
    b=mirvar_mem(mip, mem_big, 8);
    p=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(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(10));
	memset(mem_ecp, 0, MR_ECP_RESERVE(2));

	return 0;
}
