/*
 *   This program reads in GF(2^m) elliptic curve details from a .ecs file, and automatically generates
 *   ROMs containing parameters and precomputed data for a targetted processor.
 *
 *   The .ecs file may be one of the provided standard nist elliptic curves (e.g. secp192.ecs), or it can
 *   be generated by the schoof or sea applications
 *
 *   Compile on a PC using a standard MIRACL header. Note that on a 32-bit processor (i.e. MIRACL is defined as 32)
 *   this program can create ROMS for 32-bit, 16-bit and 8-bit processors. To create a ROM for a 64-bit processor
 *   this program must be compiled and run on a 64-bit processor (e.g. core 2 under Linux).
 *
 *   cl /O2 romaker2.c miracl.lib
 *
 *   The output of this program can be pasted directly into an application like ecdh2m*.c
 *
 */

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

void strip(char *name)
{ /* strip off filename extension */
    int i;
    for (i=0;name[i]!='\0';i++)
    {
        if (name[i]!='.') continue;
        name[i]='\0';
        break;
    }
}

static int answer(void)
{
    char ch;
    scanf("%c",&ch);
    getchar();
    if (ch=='Y' || ch=='y') return 1;
    return 0;
}

/* NOTE! May be necessary to change %lx in certain cases
   e.g. for Microsoft 64-bit compilers, change to %I64x */

void bprint(mr_small *n,int len,int words,int wsize,BOOL last)
{
    int i,j,k;
    BOOL first=TRUE;
    mr_small e,w=((mr_small)1<<wsize);
    for (i=k=0;i<len;i++)
    {
        e=n[i];
        if (MIRACL==wsize)
        {
            if (first)
            {
                printf("0x%lx",e);
                first=FALSE;
            }
            else printf(",0x%lx",e);
        }
        else for (j=0;j<(MIRACL/wsize);j++)
        {
            if (first)
            {
                printf("0x%lx",e%w);
                first=FALSE;
            }
            else printf(",0x%lx",e%w);
            k++;
            if (k>=words) break;
            e/=w;
        }        
    }
    if (last) printf("};\n");
    else printf(",\n");
}

int main()
{
    FILE *fp;
    int m,a,b,c;
    big e,a2,a6,x,y,r,t;
    epoint *g;
    ebrick2 binst;
    char fname[100];
    BOOL last;
    int i,j,len,bptr,nb,window,wsize,words,winsize;
    miracl *mip=mirsys(50,0);
    e=mirvar(0);
    a2=mirvar(0);
    a6=mirvar(0);
    x=mirvar(0);
    y=mirvar(0);
    r=mirvar(0);
    t=mirvar(0);

    printf("Enter name of .ecs file= ");
    gets(fname);
    strip(fname);
    strcat(fname,".ecs");

    if ((fp=fopen(fname,"rt"))==NULL)
    {
        printf("Unable to open file %s\n",fname);
        return 0;
    }
    fscanf(fp,"%d\n",&m);

    mip->IOBASE=16;
    cinnum(a2,fp);
    cinnum(a6,fp);
    cinnum(r,fp);
    cinnum(x,fp);
    cinnum(y,fp);
    mip->IOBASE=10;

    fscanf(fp,"%d\n",&a);
    fscanf(fp,"%d\n",&b);
    fscanf(fp,"%d\n",&c);
    
    printf("modulus is %d bits in length\n",m);
    nb=m;
    printf("Enter window size in bits (1-10)= ");
    scanf("%d",&window);
    getchar();
    printf("Enter word size of application processor (8, 16, 32 or 64 bit)= ");
    scanf("%d",&wsize);
    getchar();

    if (wsize!=8 && wsize!=16 && wsize!=32 && wsize!=64 || wsize>MIRACL)
    {
        printf("Error - Unsupported word size\n");
        exit(0);
    }


    if (!ebrick2_init(&binst,x,y,a2,a6,m,a,b,c,window,nb))
    {
        printf("Failed to Initialize\n");
        return 0;
    }

    len=MR_ROUNDUP(m,MIRACL);
    words=MR_ROUNDUP(m,wsize);
    printf("\n--------------------CUT HERE----------------------\n\n");
    printf("#define CURVE_M %d\n",m);
    printf("#define CURVE_A %d\n",a);
    printf("#define CURVE_B %d\n",b);
    printf("#define CURVE_C %d\n",c);
    printf("#define WINDOW %d\n",window);
    printf("#define WORDS %d\n",words);

    printf("\nstatic const mr_small rom[]={\n");

    bprint(a6->w,len,words,wsize,FALSE);
    bprint(r->w,len,words,wsize,FALSE);
    bprint(x->w,len,words,wsize,FALSE);
    bprint(y->w,len,words,wsize,TRUE);

    printf("\nstatic const mr_small prom[]={\n");
    bptr=0;
    last=FALSE;
    winsize=2*(1<<window);
    for (i=0;i<winsize;i++)
    {
        zero(t);
        t->len=len;
        for (j=0;j<len;j++)
            t->w[j]=binst.table[bptr++];
       
        if (i==winsize-1) last=TRUE;
        bprint(t->w,len,words,wsize,last);
    }


    ebrick2_end(&binst);
    
    return 0;
}


