/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
*/

/* AMCL BN Curve pairing functions */

//#define HAS_MAIN

#include "amcl.h"

/* Line function */
static void PAIR_line(FP12 *v,ECP2 *A,ECP2 *B,BIG Qx,BIG Qy)
{
    ECP2 P;
    FP2 Z3,X,Y,ZZ,T,NY;
    FP4 a,b,c;
    int D;
    ECP2_copy(&P,A);
    if (A==B)
        D=ECP2_dbl(A);  // check these return numbers...
    else
        D=ECP2_add(A,B);
    if (D<0)
    {
        /* Infinity */
        FP12_one(v);
        return;
    }

    FP2_copy(&Z3,&(A->z));
    FP4_zero(&c);
    FP2_sqr(&ZZ,&(P.z));    /* ZZ=Z^2 */
    if (D==0)
    {
        /* addition */
        ECP2_get(&X,&Y,B);
        FP2_mul(&T,&(P.z),&Y);  /* T=Z*Y2 */

        FP2_mul(&ZZ,&ZZ,&T);

        FP2_neg(&NY,&(P.y));
        FP2_add(&ZZ,&ZZ,&NY); /* ZZ=Z^3*Y2-Y (slope numerator) */
        FP2_pmul(&Z3,&Z3,Qy);    /* Z3*Qy */
        FP2_mul(&T,&T,&(P.x));
        FP2_mul(&X,&X,&NY);
        FP2_add(&T,&T,&X);       /* Z*Y2*X-X2*Y */
        FP4_from_FP2s(&a,&Z3,&T); /* a=[Z3*Qy,Z*Y2*X-X2*Y] */
        FP2_neg(&ZZ,&ZZ);
        FP2_pmul(&ZZ,&ZZ,Qx);
        FP4_from_FP2(&b,&ZZ);    /* b=-slope*Qx */
    }
    else
    {
        /* doubling */
        FP2_sqr(&T,&(P.x));
        FP2_imul(&T,&T,3);   /* T=3X^2 (slope numerator) */
        FP2_sqr(&Y,&(P.y));

        FP2_add(&Y,&Y,&Y);   /* Y=2Y^2 */
        FP2_mul(&Z3,&Z3,&ZZ);   /* Z3=Z3*ZZ */
        FP2_pmul(&Z3,&Z3,Qy);   /* Z3=Z3*ZZ*Qy */

        FP2_mul(&X,&(P.x),&T);
        FP2_sub(&X,&X,&Y);      /* X=X*slope-2Y^2 */
        FP4_from_FP2s(&a,&Z3,&X); /* a=[Z3*ZZ*Qy , X*slope-2Y^2] */
        FP2_neg(&T,&T);
        FP2_mul(&ZZ,&ZZ,&T);
        FP2_pmul(&ZZ,&ZZ,Qx);
        FP4_from_FP2(&b,&ZZ);    /* b=-slope*ZZ*Qx */
    }

    FP12_from_FP4s(v,&a,&b,&c);
}

/* Optimal R-ate pairing r=e(P,Q) */
void PAIR_ate(FP12 *r,ECP2 *P,ECP *Q)
{
    FP2 X;
    BIG x,n,Qx,Qy;
    int i,nb;
    ECP2 A;
    FP12 lv;
#if CHOICE<BLS_CURVES
    ECP2 KA;
#endif

    BIG_rcopy(Qx,CURVE_Fra);
    BIG_rcopy(Qy,CURVE_Frb);
    FP2_from_BIGs(&X,Qx,Qy);

    BIG_rcopy(x,CURVE_Bnx);

#if CHOICE<BLS_CURVES
    BIG_pmul(n,x,6);
    BIG_dec(n,2);
#else
    BIG_copy(n,x);
#endif

    BIG_norm(n);

    ECP2_affine(P);
    ECP_affine(Q);

    BIG_copy(Qx,Q->x);
    BIG_copy(Qy,Q->y);

    ECP2_copy(&A,P);
    FP12_one(r);
    nb=BIG_nbits(n);

    /* Main Miller Loop */
    for (i=nb-2; i>=1; i--)
    {
        PAIR_line(&lv,&A,&A,Qx,Qy);
        FP12_smul(r,&lv);
        if (BIG_bit(n,i))
        {

            PAIR_line(&lv,&A,P,Qx,Qy);
            FP12_smul(r,&lv);
        }
        FP12_sqr(r,r);
    }

    PAIR_line(&lv,&A,&A,Qx,Qy);
    FP12_smul(r,&lv);

    if (BIG_parity(n))
    {
        PAIR_line(&lv,&A,P,Qx,Qy);
        FP12_smul(r,&lv);
    }

    /* R-ate fixup required for BN curves */
#if CHOICE<BLS_CURVES
    ECP2_copy(&KA,P);
    ECP2_frob(&KA,&X);

    ECP2_neg(&A);
    FP12_conj(r,r);

    PAIR_line(&lv,&A,&KA,Qx,Qy);
    FP12_smul(r,&lv);
    ECP2_frob(&KA,&X);
    ECP2_neg(&KA);
    PAIR_line(&lv,&A,&KA,Qx,Qy);
    FP12_smul(r,&lv);
#endif
}

/* Optimal R-ate double pairing e(P,Q).e(R,S) */
void PAIR_double_ate(FP12 *r,ECP2 *P,ECP *Q,ECP2 *R,ECP *S)
{
    FP2 X;
    BIG x,n,Qx,Qy,Sx,Sy;
    int i,nb;
    ECP2 A,B;
    FP12 lv;
#if CHOICE<BLS_CURVES
    ECP2 K;
#endif
    BIG_rcopy(Qx,CURVE_Fra);
    BIG_rcopy(Qy,CURVE_Frb);
    FP2_from_BIGs(&X,Qx,Qy);

    BIG_rcopy(x,CURVE_Bnx);

#if CHOICE<BLS_CURVES
    BIG_pmul(n,x,6);
    BIG_dec(n,2);
#else
    BIG_copy(n,x);
#endif

    BIG_norm(n);

    ECP2_affine(P);
    ECP_affine(Q);

    ECP2_affine(R);
    ECP_affine(S);

    BIG_copy(Qx,Q->x);
    BIG_copy(Qy,Q->y);

    BIG_copy(Sx,S->x);
    BIG_copy(Sy,S->y);

    ECP2_copy(&A,P);
    ECP2_copy(&B,R);
    FP12_one(r);
    nb=BIG_nbits(n);

    /* Main Miller Loop */
    for (i=nb-2; i>=1; i--)
    {
        PAIR_line(&lv,&A,&A,Qx,Qy);
        FP12_smul(r,&lv);
        PAIR_line(&lv,&B,&B,Sx,Sy);
        FP12_smul(r,&lv);

        if (BIG_bit(n,i))
        {
            PAIR_line(&lv,&A,P,Qx,Qy);
            FP12_smul(r,&lv);

            PAIR_line(&lv,&B,R,Sx,Sy);
            FP12_smul(r,&lv);
        }
        FP12_sqr(r,r);
    }

    PAIR_line(&lv,&A,&A,Qx,Qy);
    FP12_smul(r,&lv);

    PAIR_line(&lv,&B,&B,Sx,Sy);
    FP12_smul(r,&lv);

    if (BIG_parity(n))
    {
        PAIR_line(&lv,&A,P,Qx,Qy);
        FP12_smul(r,&lv);

        PAIR_line(&lv,&B,R,Sx,Sy);
        FP12_smul(r,&lv);
    }

    /* R-ate fixup required for BN curves */
#if CHOICE<BLS_CURVES
    FP12_conj(r,r);

    ECP2_copy(&K,P);
    ECP2_frob(&K,&X);
    ECP2_neg(&A);
    PAIR_line(&lv,&A,&K,Qx,Qy);
    FP12_smul(r,&lv);
    ECP2_frob(&K,&X);
    ECP2_neg(&K);
    PAIR_line(&lv,&A,&K,Qx,Qy);
    FP12_smul(r,&lv);

    ECP2_copy(&K,R);
    ECP2_frob(&K,&X);
    ECP2_neg(&B);
    PAIR_line(&lv,&B,&K,Sx,Sy);
    FP12_smul(r,&lv);
    ECP2_frob(&K,&X);
    ECP2_neg(&K);
    PAIR_line(&lv,&B,&K,Sx,Sy);
    FP12_smul(r,&lv);
#endif
}

/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */
void PAIR_fexp(FP12 *r)
{
    FP2 X;
    BIG x,a,b;
    FP12 t0,y0,y1,y2,y3;

    BIG_rcopy(x,CURVE_Bnx);
    BIG_rcopy(a,CURVE_Fra);
    BIG_rcopy(b,CURVE_Frb);
    FP2_from_BIGs(&X,a,b);

    /* Easy part of final exp */

    FP12_inv(&t0,r);
    FP12_conj(r,r);

    FP12_mul(r,&t0);
    FP12_copy(&t0,r);

    FP12_frob(r,&X);
    FP12_frob(r,&X);
    FP12_mul(r,&t0);

    /* Hard part of final exp - see Duquesne & Ghamman eprint 2015/192.pdf */
#if CHOICE<BLS_CURVES
    FP12_pow(&t0,r,x); // t0=f^-u
    FP12_usqr(&y3,&t0); // y3=t0^2
    FP12_copy(&y0,&t0);
    FP12_mul(&y0,&y3); // y0=t0*y3
    FP12_copy(&y2,&y3);
    FP12_frob(&y2,&X); // y2=y3^p
    FP12_mul(&y2,&y3); //y2=y2*y3
    FP12_usqr(&y2,&y2); //y2=y2^2
    FP12_mul(&y2,&y3); // y2=y2*y3

    FP12_pow(&t0,&y0,x);  //t0=y0^-u
    FP12_conj(&y0,r);     //y0=~r
    FP12_copy(&y1,&t0);
    FP12_frob(&y1,&X);
    FP12_frob(&y1,&X); //y1=t0^p^2
    FP12_mul(&y1,&y0); // y1=y0*y1
    FP12_conj(&t0,&t0); // t0=~t0
    FP12_copy(&y3,&t0);
    FP12_frob(&y3,&X); //y3=t0^p
    FP12_mul(&y3,&t0); // y3=t0*y3
    FP12_usqr(&t0,&t0); // t0=t0^2
    FP12_mul(&y1,&t0); // y1=t0*y1

    FP12_pow(&t0,&y3,x); // t0=y3^-u
    FP12_usqr(&t0,&t0); //t0=t0^2
    FP12_conj(&t0,&t0); //t0=~t0
    FP12_mul(&y3,&t0); // y3=t0*y3

    FP12_frob(r,&X);
    FP12_copy(&y0,r);
    FP12_frob(r,&X);
    FP12_mul(&y0,r);
    FP12_frob(r,&X);
    FP12_mul(&y0,r);

    FP12_usqr(r,&y3);  //r=y3^2
    FP12_mul(r,&y2);   //r=y2*r
    FP12_copy(&y3,r);
    FP12_mul(&y3,&y0); // y3=r*y0
    FP12_mul(r,&y1); // r=r*y1
    FP12_usqr(r,r); // r=r^2
    FP12_mul(r,&y3); // r=r*y3
    FP12_reduce(r);
#else
// Ghamman & Fouotsa Method

    FP12_usqr(&y0,r);
    FP12_pow(&y1,&y0,x);
    BIG_fshr(x,1);
    FP12_pow(&y2,&y1,x);
    BIG_fshl(x,1); // x must be even
    FP12_conj(&y3,r);
    FP12_mul(&y1,&y3);

    FP12_conj(&y1,&y1);
    FP12_mul(&y1,&y2);

    FP12_pow(&y2,&y1,x);

    FP12_pow(&y3,&y2,x);
    FP12_conj(&y1,&y1);
    FP12_mul(&y3,&y1);

    FP12_conj(&y1,&y1);
    FP12_frob(&y1,&X);
    FP12_frob(&y1,&X);
    FP12_frob(&y1,&X);
    FP12_frob(&y2,&X);
    FP12_frob(&y2,&X);
    FP12_mul(&y1,&y2);

    FP12_pow(&y2,&y3,x);
    FP12_mul(&y2,&y0);
    FP12_mul(&y2,r);

    FP12_mul(&y1,&y2);
    FP12_copy(&y2,&y3);
    FP12_frob(&y2,&X);
    FP12_mul(&y1,&y2);
    FP12_copy(r,&y1);
    FP12_reduce(r);

// Aranha et al method as described by Ghamman & Fouotsa
    /*
    	FP12_usqr(&y0,r);  // t0=f^2
    	FP12_conj(&y3,&y0); // t0=f^-2
    	FP12_pow(&t0,r,x); // t5=f^u
    	FP12_usqr(&y1,&t0); // t1=t5^2
    	FP12_mul(&y3,&t0); // t3=t0*t5

    	FP12_pow(&y0,&y3,x);

    	FP12_pow(&y2,&y0,x);

    	FP12_pow(&y4,&y2,x);

    	FP12_mul(&y4,&y1);
    	FP12_pow(&y1,&y4,x);
    	FP12_conj(&y3,&y3);
    	FP12_mul(&y1,&y3);
    	FP12_mul(&y1,r);

    	FP12_conj(&y3,r);
    	FP12_mul(&y0,r);
    	FP12_frob(&y0,&X); FP12_frob(&y0,&X); FP12_frob(&y0,&X);

    	FP12_mul(&y4,&y3);
    	FP12_frob(&y4,&X);

    	FP12_mul(&t0,&y2);
    	FP12_frob(&t0,&X); FP12_frob(&t0,&X);

    	FP12_mul(&t0,&y0);
    	FP12_mul(&t0,&y4);
    	FP12_mul(&t0,&y1);
    	FP12_copy(r,&t0);
    	FP12_reduce(r);*/

//-----------------------------------
    /*
    	FP12_copy(&y0,r);						// y0=r;
    	FP12_copy(&y1,r);						// y1=r;
    	FP12_copy(&t0,r); FP12_frob(&t0,&X);	// t0=Frobenius(r,X,1);
    	FP12_conj(&y3,&t0); FP12_mul(&y1,&y3);	// y1*=inverse(t0);
    	FP12_frob(&t0,&X); FP12_frob(&t0,&X);	// t0=Frobenius(t0,X,2);
    	FP12_mul(&y1,&t0);						// y1*=t0;

    	FP12_pow(r,r,x);						// r=pow(r,x);
    	FP12_conj(&y3,r); FP12_mul(&y1,&y3);	// y1*=inverse(r);
    	FP12_copy(&t0,r); FP12_frob(&t0,&X);	// t0=Frobenius(r,X,1);
    	FP12_mul(&y0,&t0);						// y0*=t0;
    	FP12_frob(&t0,&X);						// t0=Frobenius(t0,X,1);
    	FP12_mul(&y1,&t0);						// y1*=t0;
    	FP12_frob(&t0,&X);						// t0=Frobenius(t0,X,1);
    	FP12_conj(&y3,&t0); FP12_mul(&y0,&y3);	// y0*=inverse(t0);

    	FP12_pow(r,r,x);						// r=pow(r,x);
    	FP12_mul(&y0,r);						// y0*=r;
    	FP12_copy(&t0,r); FP12_frob(&t0,&X); FP12_frob(&t0,&X); // t0=Frobenius(r,X,2);
    	FP12_conj(&y3,&t0); FP12_mul(&y0,&y3);	// y0*=inverse(t0);
    	FP12_frob(&t0,&X);						// t0=Frobenius(t0,X,1);
    	FP12_mul(&y1,&t0);						// y1*=t0;

    	FP12_pow(r,r,x);						// r=pow(r,x);			// r^x3
    	FP12_copy(&t0,r); FP12_frob(&t0,&X);	// t0=Frobenius(r,X,1);
    	FP12_conj(&y3,&t0); FP12_mul(&y0,&y3);	// y0*=inverse(t0);
    	FP12_frob(&t0,&X);						// t0=Frobenius(t0,X,1);
    	FP12_mul(&y1,&t0);						// y1*=t0;

    	FP12_pow(r,r,x);						// r=pow(r,x);			// r^x4
    	FP12_conj(&y3,r); FP12_mul(&y0,&y3);	// y0*=inverse(r);
    	FP12_copy(&t0,r); FP12_frob(&t0,&X);	// t0=Frobenius(r,X,1);
    	FP12_mul(&y1,&t0);						//y1*=t0;

    	FP12_pow(r,r,x);						// r=pow(r,x);			// r^x5
    	FP12_mul(&y1,r);						// y1*=r;

    	FP12_usqr(&y0,&y0);						// r=y0*y0*y1;
    	FP12_mul(&y0,&y1);
    	FP12_copy(r,&y0);
    	FP12_reduce(r); */
#endif
}

#ifdef USE_GLV
/* GLV method */
static void glv(BIG u[2],BIG e)
{
#if CHOICE<BLS_CURVES
    int i,j;
    BIG v[2],t,q;
    DBIG d;
    BIG_rcopy(q,CURVE_Order);
    for (i=0; i<2; i++)
    {
        BIG_rcopy(t,CURVE_W[i]);
//BIG_norm(t); BIG_norm(e);
        BIG_mul(d,t,e);
        BIG_ddiv(v[i],d,q);
        BIG_zero(u[i]);
    }
    BIG_copy(u[0],e);
    for (i=0; i<2; i++)
        for (j=0; j<2; j++)
        {
            BIG_rcopy(t,CURVE_SB[j][i]);
            BIG_modmul(t,v[j],t,q);
            BIG_add(u[i],u[i],q);
            BIG_sub(u[i],u[i],t);
            BIG_mod(u[i],q);
        }

#else
// -(x^2).P = (Beta.x,y)

    BIG x,x2,q;
    BIG_rcopy(x,CURVE_Bnx);
    BIG_smul(x2,x,x);
    BIG_copy(u[0],e);
    BIG_mod(u[0],x2);
    BIG_copy(u[1],e);
    BIG_sdiv(u[1],x2);

    BIG_rcopy(q,CURVE_Order);
    BIG_sub(u[1],q,u[1]);

#endif

    return;
}
#endif // USE_GLV

/* Galbraith & Scott Method */
static void gs(BIG u[4],BIG e)
{
    int i;
#if CHOICE<BLS_CURVES
    int j;
    BIG v[4],t,q;
    DBIG d;
    BIG_rcopy(q,CURVE_Order);
    for (i=0; i<4; i++)
    {
        BIG_rcopy(t,CURVE_WB[i]);
//BIG_norm(t); BIG_norm(e);
        BIG_mul(d,t,e);
        BIG_ddiv(v[i],d,q);
        BIG_zero(u[i]);
    }

    BIG_copy(u[0],e);
    for (i=0; i<4; i++)
        for (j=0; j<4; j++)
        {
            BIG_rcopy(t,CURVE_BB[j][i]);
            BIG_modmul(t,v[j],t,q);
            BIG_add(u[i],u[i],q);
            BIG_sub(u[i],u[i],t);
            BIG_mod(u[i],q);
        }

#else

    BIG x,w;
    BIG_rcopy(x,CURVE_Bnx);
    BIG_copy(w,e);

    for (i=0; i<4; i++)
    {
        BIG_copy(u[i],w);
        BIG_mod(u[i],x);
        BIG_sdiv(w,x);
    }

#endif
    return;
}

/* Multiply P by e in group G1 */
void PAIR_G1mul(ECP *P,BIG e)
{
#ifdef USE_GLV   /* Note this method is patented */
    int np,nn;
    ECP Q;
    BIG cru,t,q;
    BIG u[2];

    BIG_rcopy(q,CURVE_Order);
    glv(u,e);

    ECP_affine(P);
    ECP_copy(&Q,P);
    BIG_rcopy(cru,CURVE_Cru);
    FP_nres(cru);
    FP_mul(Q.x,Q.x,cru);

    /* note that -a.B = a.(-B). Use a or -a depending on which is smaller */

    np=BIG_nbits(u[0]);
    BIG_modneg(t,u[0],q);
    nn=BIG_nbits(t);
    if (nn<np)
    {
        BIG_copy(u[0],t);
        ECP_neg(P);
    }

    np=BIG_nbits(u[1]);
    BIG_modneg(t,u[1],q);
    nn=BIG_nbits(t);
    if (nn<np)
    {
        BIG_copy(u[1],t);
        ECP_neg(&Q);
    }

    ECP_mul2(P,&Q,u[0],u[1]);

#else
    ECP_mul(P,e);
#endif
}

/* Multiply P by e in group G2 */
void PAIR_G2mul(ECP2 *P,BIG e)
{
#ifdef USE_GS_G2   /* Well I didn't patent it :) */
    int i,np,nn;
    ECP2 Q[4];
    FP2 X;
    BIG x,y;
    BIG u[4];

    BIG_rcopy(x,CURVE_Fra);
    BIG_rcopy(y,CURVE_Frb);
    FP2_from_BIGs(&X,x,y);

    BIG_rcopy(y,CURVE_Order);
    gs(u,e);


    ECP2_affine(P);

    ECP2_copy(&Q[0],P);
    for (i=1; i<4; i++)
    {
        ECP2_copy(&Q[i],&Q[i-1]);
        ECP2_frob(&Q[i],&X);
    }

    for (i=0; i<4; i++)
    {
        np=BIG_nbits(u[i]);
        BIG_modneg(x,u[i],y);
        nn=BIG_nbits(x);
        if (nn<np)
        {
            BIG_copy(u[i],x);
            ECP2_neg(&Q[i]);
        }
    }

    ECP2_mul4(P,Q,u);

#else
    ECP2_mul(P,e);
#endif
}

/* f=f^e */
void PAIR_GTpow(FP12 *f,BIG e)
{
#ifdef USE_GS_GT   /* Note that this option requires a lot of RAM! Maybe better to use compressed XTR method, see fp4.c */
    int i,np,nn;
    FP12 g[4];
    FP2 X;
    BIG t,q,x,y;
    BIG u[4];

    BIG_rcopy(x,CURVE_Fra);
    BIG_rcopy(y,CURVE_Frb);
    FP2_from_BIGs(&X,x,y);

    BIG_rcopy(q,CURVE_Order);
    gs(u,e);

    FP12_copy(&g[0],f);
    for (i=1; i<4; i++)
    {
        FP12_copy(&g[i],&g[i-1]);
        FP12_frob(&g[i],&X);
    }

    for (i=0; i<4; i++)
    {
        np=BIG_nbits(u[i]);
        BIG_modneg(t,u[i],q);
        nn=BIG_nbits(t);
        if (nn<np)
        {
            BIG_copy(u[i],t);
            FP12_conj(&g[i],&g[i]);
        }
    }
    FP12_pow4(f,g,u);

#else
    FP12_pow(f,f,e);
#endif
}

/* test group membership test - no longer needed */
/* with GT-Strong curve, now only check that m!=1, conj(m)*m==1, and m.m^{p^4}=m^{p^2} */

/*
int PAIR_GTmember(FP12 *m)
{
	BIG a,b;
	FP2 X;
	FP12 r,w;
	if (FP12_isunity(m)) return 0;
	FP12_conj(&r,m);
	FP12_mul(&r,m);
	if (!FP12_isunity(&r)) return 0;

	BIG_rcopy(a,CURVE_Fra);
	BIG_rcopy(b,CURVE_Frb);
	FP2_from_BIGs(&X,a,b);


	FP12_copy(&r,m); FP12_frob(&r,&X); FP12_frob(&r,&X);
	FP12_copy(&w,&r); FP12_frob(&w,&X); FP12_frob(&w,&X);
	FP12_mul(&w,m);


#ifndef GT_STRONG
	if (!FP12_equals(&w,&r)) return 0;

	BIG_rcopy(a,CURVE_Bnx);

	FP12_copy(&r,m); FP12_pow(&w,&r,a); FP12_pow(&w,&w,a);
	FP12_sqr(&r,&w); FP12_mul(&r,&w); FP12_sqr(&r,&r);

	FP12_copy(&w,m); FP12_frob(&w,&X);
 #endif

	return FP12_equals(&w,&r);
}

*/


#ifdef HAS_MAIN
/*
#if CHOICE==BN254_T

const BIG TEST_Gx={0x18AFF11A,0xF2EF406,0xAF68220,0x171F2E27,0x6BA0959,0x124C50E0,0x450BE27,0x7003EA8,0x8A914};
const BIG TEST_Gy={0x6E010F4,0xA71D07E,0x7ECADA8,0x8260E8E,0x1F79C328,0x17A09412,0xBFAE690,0x1C57CBD1,0x17DF54};

const BIG TEST_Pxa={0x1047D566,0xD83CD71,0x10322E9D,0x991FA93,0xA282C48,0x18AEBEC8,0xCB05850,0x13B4F669,0x21794A};
const BIG TEST_Pxb={0x1E305936,0x16885BF1,0x327060,0xE26F794,0x1547D870,0x1963E5B2,0x1BEBB96C,0x988A33C,0x1A9B47};
const BIG TEST_Pya={0x20FF876,0x4427E67,0x18732211,0xE88E45E,0x174D1A7E,0x17D877ED,0x343AB37,0x97EB453,0xB00D5};
const BIG TEST_Pyb={0x1D746B7B,0x732F4C2,0x122A49B0,0x16267985,0x235DF56,0x10B1E4D,0x14D8F210,0x17A05C3E,0x5ECF8};

#endif

#if CHOICE==BN254_T2

const BIG TEST_Gx={0x15488765,0x46790D7,0xD9900A,0x1DFB43F,0x9F2D307,0xC4724E8,0x5678E51,0x15C3E3A7,0x1BEC8E};
const BIG TEST_Gy={0x3D3273C,0x1AFA5FF,0x1880A139,0xACD34DF,0x17493067,0x10FA4103,0x1D4C9766,0x1A73F3DB,0x2D148};

const BIG TEST_Pxa={0xF8DC275,0xAC27FA,0x11815151,0x152691C8,0x5CDEBF1,0x7D5A965,0x1BF70CE3,0x679A1C8,0xD62CF};
const BIG TEST_Pxb={0x1D17D7A8,0x6B28DF4,0x174A0389,0xFE67E5F,0x1FA97A3C,0x7F5F473,0xFFB5146,0x4BC19A5,0x227010};
const BIG TEST_Pya={0x16CC1F90,0x5284627,0x171B91AB,0x11F843B9,0x1D468755,0x67E279C,0x19FE0EF8,0x1A0CAA6B,0x1CC6CB};
const BIG TEST_Pyb={0x1FF0CF2A,0xBC83255,0x6DD6EE8,0xB8B752F,0x13E484EC,0x1809BE81,0x1A648AA1,0x8CEF3F3,0x86EE};


#endif

#if CHOICE==BN254

const BIG TEST_Gx={0x14BEC4670E4EB7,0xEA2973860F6861,0x35C14B2FC3C28F,0x4402A0B63B9473,0x2074A81D};
const BIG TEST_Gy={0xC284846631CBEB,0x34A6E8D871B3B,0x89FB94A82B2006,0x87B20038771FC,0x6A41108};

const BIG TEST_Pxa={0xE4A00F52183C77,0x554E02DF4F8354,0xB65EB5CF1C2F89,0x8B71A87BFCFC9,0x49EEDB1};
const BIG TEST_Pxb={0xCFB8FA9AA8845D,0x8A9CC76D966697,0x185BA05BF5EC08,0x76140E87D97226,0x1FB93AB6};
const BIG TEST_Pya={0x3644CC1EDF208A,0xA637FB3FF8E257,0x4453DA2BB9E686,0xD14AD3CDF6A1FE,0xCD04A1E};
const BIG TEST_Pyb={0x71BD7630A43C14,0x1CAA9F14EA264E,0x3C3C2DFC765DEF,0xCF59D1A1A7D6EE,0x11FF7795};


#endif
*/
int main()
{
    int i;
    char byt[32];
    csprng rng;
    BIG xa,xb,ya,yb,w,a,b,t1,q,u[2],v[4],m,r;
    ECP2 P,G;
    ECP Q,R;
    FP12 g,gp;
    FP4 t,c,cp,cpm1,cpm2;
    FP2 x,y,X;


    BIG_rcopy(a,CURVE_Fra);
    BIG_rcopy(b,CURVE_Frb);
    FP2_from_BIGs(&X,a,b);

    BIG_rcopy(xa,CURVE_Gx);
    BIG_rcopy(ya,CURVE_Gy);

    ECP_set(&Q,xa,ya);
    if (Q.inf) printf("Failed to set - point not on curve\n");
    else printf("G1 set success\n");

    printf("Q= ");
    ECP_output(&Q);
    printf("\n");

//	BIG_rcopy(r,CURVE_Order); BIG_dec(r,7); BIG_norm(r);
    BIG_rcopy(xa,CURVE_Pxa);
    BIG_rcopy(xb,CURVE_Pxb);
    BIG_rcopy(ya,CURVE_Pya);
    BIG_rcopy(yb,CURVE_Pyb);

    FP2_from_BIGs(&x,xa,xb);
    FP2_from_BIGs(&y,ya,yb);

    ECP2_set(&P,&x,&y);
    if (P.inf) printf("Failed to set - point not on curve\n");
    else printf("G2 set success\n");

    printf("P= ");
    ECP2_output(&P);
    printf("\n");

    for (i=0; i<1000; i++ )
    {

        PAIR_ate(&g,&P,&Q);
        PAIR_fexp(&g);

//	PAIR_GTpow(&g,xa);

    }
    printf("g= ");
    FP12_output(&g);
    printf("\n");

}

#endif
