http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto-c/blob/8d28d2c3/src/mpin192.c.in ---------------------------------------------------------------------- diff --git a/src/mpin192.c.in b/src/mpin192.c.in new file mode 100644 index 0000000..ee88145 --- /dev/null +++ b/src/mpin192.c.in @@ -0,0 +1,952 @@ +/* +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. +*/ + +/* MPIN Functions */ + +/* Version 3.0 - supports Time Permits */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "mpin192_ZZZ.h" + +#define ROUNDUP(a,b) ((a)-1)/(b)+1 + +/* Special mpin hashing */ +static void mpin_hash(int sha,FP8_YYY *f, ECP_ZZZ *P,octet *w) +{ + int i; + BIG_XXX x,y; + char h[64]; + hash256 sha256; + hash512 sha512; + char t[10*MODBYTES_XXX]; // to hold 10 BIGs + int hlen=sha; + + + FP_YYY_redc(x,&(f->a.a.a)); + BIG_XXX_toBytes(&t[0],x); + FP_YYY_redc(x,&(f->a.a.b)); + BIG_XXX_toBytes(&t[MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.a)); + BIG_XXX_toBytes(&t[2*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.b)); + BIG_XXX_toBytes(&t[3*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.a.a)); + BIG_XXX_toBytes(&t[4*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.a.b)); + BIG_XXX_toBytes(&t[5*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.a)); + BIG_XXX_toBytes(&t[6*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.b)); + BIG_XXX_toBytes(&t[7*MODBYTES_XXX],x); + + ECP_ZZZ_get(x,y,P); + BIG_XXX_toBytes(&t[8*MODBYTES_XXX],x); + BIG_XXX_toBytes(&t[9*MODBYTES_XXX],y); + + OCT_empty(w); + switch (sha) + { + case SHA256: + HASH256_init(&sha256); + for (i=0; i<10*MODBYTES_XXX; i++) HASH256_process(&sha256,t[i]); + HASH256_hash(&sha256,h); + break; + case SHA384: + HASH384_init(&sha512); + for (i=0; i<10*MODBYTES_XXX; i++) HASH384_process(&sha512,t[i]); + HASH384_hash(&sha512,h); + break; + case SHA512: + HASH512_init(&sha512); + for (i=0; i<10*MODBYTES_XXX; i++) HASH512_process(&sha512,t[i]); + HASH512_hash(&sha512,h); + break; + } + + OCT_jbytes(w,h,AESKEY_ZZZ); + for (i=0; i<hlen; i++) h[i]=0; +} + +/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* maps a random u to a point on the curve */ +static void map(ECP_ZZZ *P,BIG_XXX u,int cb) +{ + BIG_XXX x,q; + + BIG_XXX_rcopy(q,Modulus_YYY); + BIG_XXX_copy(x,u); + BIG_XXX_mod(x,q); + + while (!ECP_ZZZ_setx(P,x,cb)) + { + BIG_XXX_inc(x,1); + BIG_XXX_norm(x); + } +} + +/* returns u derived from P. Random value in range 1 to return value should then be added to u */ +static int unmap(BIG_XXX u,int *cb,ECP_ZZZ *P) +{ + int s,r=0; + BIG_XXX x; + + s=ECP_ZZZ_get(x,x,P); + BIG_XXX_copy(u,x); + do + { + BIG_XXX_dec(u,1); + BIG_XXX_norm(u); + r++; + } + while (!ECP_ZZZ_setx(P,u,s)); + ECP_ZZZ_setx(P,x,s); + + *cb=s; + + return r; +} + +/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ +/* Note that u and v are indistinguisible from random strings */ +int MPIN_ZZZ_ENCODING(csprng *RNG,octet *E) +{ + int rn,m,su,sv,res=0; + + BIG_XXX q,u,v; + ECP_ZZZ P,W; + + if (!ECP_ZZZ_fromOctet(&P,E)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_rcopy(q,Modulus_YYY); + + BIG_XXX_randomnum(u,q,RNG); + + su=RAND_byte(RNG); + if (su<0) su=-su; + su%=2; + map(&W,u,su); + ECP_ZZZ_sub(&P,&W); + + rn=unmap(v,&sv,&P); + m=RAND_byte(RNG); + if (m<0) m=-m; + m%=rn; + BIG_XXX_inc(v,m+1); + E->val[0]=su+2*sv; + BIG_XXX_toBytes(&(E->val[1]),u); + BIG_XXX_toBytes(&(E->val[PFS_ZZZ+1]),v); + } + return res; +} + +int MPIN_ZZZ_DECODING(octet *D) +{ + int su,sv; + BIG_XXX u,v; + ECP_ZZZ P,W; + int res=0; + + if ((D->val[0]&0x04)!=0) res=MPIN_INVALID_POINT; + if (res==0) + { + + BIG_XXX_fromBytes(u,&(D->val[1])); + BIG_XXX_fromBytes(v,&(D->val[PFS_ZZZ+1])); + + su=D->val[0]&1; + sv=(D->val[0]>>1)&1; + map(&W,u,su); + map(&P,v,sv); + ECP_ZZZ_add(&P,&W); + ECP_ZZZ_toOctet(D,&P); + } + + return res; +} + +/* R=R1+R2 in group G1 */ +int MPIN_ZZZ_RECOMBINE_G1(octet *R1,octet *R2,octet *R) +{ + ECP_ZZZ P,T; + int res=0; + if (res==0) + { + if (!ECP_ZZZ_fromOctet(&P,R1)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&T,R2)) res=MPIN_INVALID_POINT; + } + if (res==0) + { + ECP_ZZZ_add(&P,&T); + ECP_ZZZ_toOctet(R,&P); + } + return res; +} + +/* W=W1+W2 in group G2 */ +int MPIN_ZZZ_RECOMBINE_G2(octet *W1,octet *W2,octet *W) +{ + ECP4_ZZZ Q,T; + int res=0; + if (!ECP4_ZZZ_fromOctet(&Q,W1)) res=MPIN_INVALID_POINT; + if (!ECP4_ZZZ_fromOctet(&T,W2)) res=MPIN_INVALID_POINT; + if (res==0) + { + ECP4_ZZZ_add(&Q,&T); + ECP4_ZZZ_toOctet(W,&Q); + } + return res; +} + +/* create random secret S */ +int MPIN_ZZZ_RANDOM_GENERATE(csprng *RNG,octet* S) +{ + BIG_XXX r,s; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(s,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(s,2*AES_S); +#endif + BIG_XXX_toBytes(S->val,s); + S->len=MODBYTES_XXX; + return 0; +} + +/* Extract PIN from TOKEN for identity CID */ +int MPIN_ZZZ_EXTRACT_PIN(int sha,octet *CID,int pin,octet *TOKEN) +{ + pin%=MAXPIN; + return MPIN_ZZZ_EXTRACT_FACTOR(sha,CID,pin,PBLEN,TOKEN); +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_EXTRACT_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_sub(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P); + } + return res; +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_RESTORE_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_add(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P); + } + return res; +} + +/* Implement step 2 on client side of MPin protocol - SEC=-(x+y)*SEC */ +int MPIN_ZZZ_CLIENT_2(octet *X,octet *Y,octet *SEC) +{ + BIG_XXX px,py,r; + ECP_ZZZ P; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (!ECP_ZZZ_fromOctet(&P,SEC)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_fromBytes(px,X->val); + BIG_XXX_fromBytes(py,Y->val); + BIG_XXX_add(px,px,py); + BIG_XXX_mod(px,r); + // BIG_XXX_sub(px,r,px); + PAIR_ZZZ_G1mul(&P,px); + ECP_ZZZ_neg(&P); + ECP_ZZZ_toOctet(SEC,&P); + } + return res; +} + +/* + W=x*H(G); + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +*/ + +int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP_ZZZ P; + BIG_XXX r,x; + int res=0; + if (RNG!=NULL) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + if (type==0) + { + if (!ECP_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + } + else + { + ECP_ZZZ_mapit(&P,G); + } + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,x); + ECP_ZZZ_toOctet(W,&P); + } + return res; +} + +/* + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + W=x*G where G is point on the curve + if type==1 W=(x^-1)G +*/ + +int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP4_ZZZ P; + BIG_XXX r,x; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + { + BIG_XXX_fromBytes(x,X->val); + if (type==1) BIG_XXX_invmodp(x,x,r); + } + + if (!ECP4_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + + if (res==0) + { + PAIR_ZZZ_G2mul(&P,x); + ECP4_ZZZ_toOctet(W,&P); + } + return res; +} + + + +/* Client secret CST=s*H(CID) where CID is client ID and s is master secret */ +/* CID is hashed externally */ +int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *CID,octet *CST) +{ + return MPIN_ZZZ_GET_G1_MULTIPLE(NULL,1,S,CID,CST); +} + +/* Implement step 1 on client side of MPin protocol */ +int MPIN_ZZZ_CLIENT_1(int sha,int date,octet *CLIENT_ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *SEC,octet *xID,octet *xCID,octet *PERMIT) +{ + BIG_XXX r,x; + ECP_ZZZ P,T,W; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + mhashit(sha,-1,CLIENT_ID,&H); + + ECP_ZZZ_mapit(&P,&H); + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + pin%=MAXPIN; + + ECP_ZZZ_copy(&W,&P); // W=H(ID) + ECP_ZZZ_pinmul(&W,pin,PBLEN); // W=alpha.H(ID) + ECP_ZZZ_add(&T,&W); // T=Token+alpha.H(ID) = s.H(ID) + + if (date) + { + if (PERMIT!=NULL) + { + if (!ECP_ZZZ_fromOctet(&W,PERMIT)) res=MPIN_INVALID_POINT; + ECP_ZZZ_add(&T,&W); // SEC=s.H(ID)+s.H(T|ID) + } + mhashit(sha,date,&H,&H); + + ECP_ZZZ_mapit(&W,&H); + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P); // xID + PAIR_ZZZ_G1mul(&W,x); // W=x.H(T|ID) + ECP_ZZZ_add(&P,&W); + } + else + { + ECP_ZZZ_add(&P,&W); + PAIR_ZZZ_G1mul(&P,x); + } + if (xCID!=NULL) ECP_ZZZ_toOctet(xCID,&P); // U + } + else + { + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P); // xID + } + } + } + + if (res==0) + ECP_ZZZ_toOctet(SEC,&T); // V + + return res; +} + +/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ +int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SST) +{ + BIG_XXX r,s; + ECP4_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + ECP4_ZZZ_generator(&Q); + + if (res==0) + { + BIG_XXX_fromBytes(s,S->val); + PAIR_ZZZ_G2mul(&Q,s); + ECP4_ZZZ_toOctet(SST,&Q); + } + + return res; +} + + +/* Time Permit CTT=s*H(date|H(CID)) where s is master secret */ +int MPIN_ZZZ_GET_CLIENT_PERMIT(int sha,int date,octet *S,octet *CID,octet *CTT) +{ + BIG_XXX s; + ECP_ZZZ P; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,date,CID,&H); + + ECP_ZZZ_mapit(&P,&H); + + BIG_XXX_fromBytes(s,S->val); + + PAIR_ZZZ_G1mul(&P,s); + + ECP_ZZZ_toOctet(CTT,&P); + return 0; +} + +// if date=0 only use HID, set HCID=NULL +// if date and PE, use HID and HCID + +/* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits set HTID=NULL */ +void MPIN_ZZZ_SERVER_1(int sha,int date,octet *CID,octet *HID,octet *HTID) +{ + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + ECP_ZZZ P,R; + +#ifdef USE_ANONYMOUS + ECP_ZZZ_mapit(&P,CID); +#else + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&P,&H); +#endif + + ECP_ZZZ_toOctet(HID,&P); // new + + if (date) + { +#ifdef USE_ANONYMOUS + mhashit(sha,date,CID,&H); +#else + mhashit(sha,date,&H,&H); +#endif + ECP_ZZZ_mapit(&R,&H); + ECP_ZZZ_add(&P,&R); + ECP_ZZZ_toOctet(HTID,&P); + } +} + +/* Implement M-Pin on server side */ +int MPIN_ZZZ_SERVER_2(int date,octet *HID,octet *HTID,octet *Y,octet *SST,octet *xID,octet *xCID,octet *mSEC,octet *E,octet *F,octet *Pa) +{ + BIG_XXX px,py,y; + FP24_YYY g; + ECP4_ZZZ Q,sQ; + ECP_ZZZ P,R; + int res=0; + + ECP4_ZZZ_generator(&Q); + + // key-escrow less scheme: use Pa instead of Q in pairing computation + // Q left for backward compatiblity + if (Pa!=NULL) + { + if (!ECP4_ZZZ_fromOctet(&Q, Pa)) res=MPIN_INVALID_POINT; + } + + + if (res==0) + { + if (!ECP4_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + } + + if (res==0) + { + if (date) + { + BIG_XXX_fromBytes(px,&(xCID->val[1])); + BIG_XXX_fromBytes(py,&(xCID->val[PFS_ZZZ+1])); + } + else + { + BIG_XXX_fromBytes(px,&(xID->val[1])); + BIG_XXX_fromBytes(py,&(xID->val[PFS_ZZZ+1])); + } + if (!ECP_ZZZ_set(&R,px,py)) res=MPIN_INVALID_POINT; // x(A+AT) + } + if (res==0) + { + BIG_XXX_fromBytes(y,Y->val); + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HTID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // y(A+AT) + ECP_ZZZ_add(&P,&R); // x(A+AT)+y(A+T) + ECP_ZZZ_affine(&P); + if (!ECP_ZZZ_fromOctet(&R,mSEC)) res=MPIN_INVALID_POINT; // V + } + if (res==0) + { + + PAIR_ZZZ_double_ate(&g,&Q,&R,&sQ,&P); + PAIR_ZZZ_fexp(&g); + + if (!FP24_YYY_isunity(&g)) + { + if (HID!=NULL && xID!=NULL && E!=NULL && F !=NULL) + { + /* xID is set to NULL if there is no way to calculate PIN error */ + FP24_YYY_toOctet(E,&g); + + /* Note error is in the PIN, not in the time permit! Hence the need to exclude Time Permit from this check */ + + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; // U + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // yA + ECP_ZZZ_add(&P,&R); // yA+xA + ECP_ZZZ_affine(&P); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP24_YYY_toOctet(F,&g); + } + } + res=MPIN_BAD_PIN; + } + } + + return res; +} + +#if MAXPIN==10000 +#define MR_TS 10 /* 2^10/10 approx = sqrt(MAXPIN) */ +#define TRAP 200 /* 2*sqrt(MAXPIN) */ +#endif + +#if MAXPIN==1000000 +#define MR_TS 14 +#define TRAP 2000 +#endif + +/* Pollards kangaroos used to return PIN error */ +int MPIN_ZZZ_KANGAROO(octet *E,octet *F) +{ + int i,j,m,s,dn,dm,steps; + int distance[MR_TS]; + FP24_YYY ge,gf,t,table[MR_TS]; + int res=0; + // BIG_XXX w; + + FP24_YYY_fromOctet(&ge,E); + FP24_YYY_fromOctet(&gf,F); + + FP24_YYY_copy(&t,&gf); + + for (s=1,m=0; m<MR_TS; m++) + { + distance[m]=s; + FP24_YYY_copy(&table[m],&t); + s*=2; + FP24_YYY_usqr(&t,&t); + FP24_YYY_reduce(&t); + } + + FP24_YYY_one(&t); + + for (dn=0,j=0; j<TRAP; j++) + { + i=t.a.a.a.a.g[0]%MR_TS; + + FP24_YYY_mul(&t,&table[i]); + FP24_YYY_reduce(&t); + dn+=distance[i]; + } + + FP24_YYY_conj(&gf,&t); + steps=0; + dm=0; + while (dm-dn<MAXPIN) + { + steps++; + if (steps>4*TRAP) break; + + i=ge.a.a.a.a.g[0]%MR_TS; + + FP24_YYY_mul(&ge,&table[i]); + FP24_YYY_reduce(&ge); + dm+=distance[i]; + if (FP24_YYY_equals(&ge,&t)) + { + res=dm-dn; + break; + } + if (FP24_YYY_equals(&ge,&gf)) + { + res=dn-dm; + break; + } + } + if (steps>4*TRAP || dm-dn>=MAXPIN) + { + res=0; /* Trap Failed - probable invalid token */ + } + + return res; +} + +/* Functions to support M-Pin Full */ + +int MPIN_ZZZ_PRECOMPUTE(octet *TOKEN,octet *CID,octet *CP,octet *G1,octet *G2) +{ + ECP_ZZZ P,T; + ECP4_ZZZ Q; + FP24_YYY g; + int res=0; + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + ECP_ZZZ_mapit(&P,CID); + if (CP!=NULL) + { + if (!ECP4_ZZZ_fromOctet(&Q,CP)) res=MPIN_INVALID_POINT; + } + else + { + ECP4_ZZZ_generator(&Q); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&T); + PAIR_ZZZ_fexp(&g); + + FP24_YYY_toOctet(G1,&g); + if (G2!=NULL) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP24_YYY_toOctet(G2,&g); + } + } + return res; +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +int MPIN_ZZZ_CLIENT_KEY(int sha,octet *G1,octet *G2,int pin,octet *R,octet *X,octet *H,octet *wCID,octet *CK) +{ + FP24_YYY g1,g2; + FP8_YYY c; + + ECP_ZZZ W; + int res=0; + BIG_XXX r,z,x,h; + + FP24_YYY_fromOctet(&g1,G1); + FP24_YYY_fromOctet(&g2,G2); + BIG_XXX_fromBytes(z,R->val); + BIG_XXX_fromBytes(x,X->val); + BIG_XXX_fromBytes(h,H->val); + + if (!ECP_ZZZ_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT; + + if (res==0) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_add(z,z,h); // new + BIG_XXX_mod(z,r); + + FP24_YYY_pinpow(&g2,pin,PBLEN); + FP24_YYY_mul(&g1,&g2); + + PAIR_ZZZ_G1mul(&W,x); + + FP24_YYY_compow(&c,&g1,z,r); + mpin_hash(sha,&c,&W,CK); + + } + return res; +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +int MPIN_ZZZ_SERVER_KEY(int sha,octet *Z,octet *SST,octet *W,octet *H,octet *HID,octet *xID,octet *xCID,octet *SK) +{ + int res=0; + FP24_YYY g; + FP8_YYY c; + ECP_ZZZ R,U,A; + ECP4_ZZZ sQ; + BIG_XXX w,h; + + if (!ECP4_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,Z)) res=MPIN_INVALID_POINT; + + + if (!ECP_ZZZ_fromOctet(&A,HID)) res=MPIN_INVALID_POINT; + + // new + if (xCID!=NULL) + { + if (!ECP_ZZZ_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&U,xID)) res=MPIN_INVALID_POINT; + } + BIG_XXX_fromBytes(w,W->val); + BIG_XXX_fromBytes(h,H->val); + + + PAIR_ZZZ_ate(&g,&sQ,&A); + PAIR_ZZZ_fexp(&g); + + if (res==0) + { + PAIR_ZZZ_G1mul(&A,h); + ECP_ZZZ_add(&R,&A); // new + ECP_ZZZ_affine(&R); + PAIR_ZZZ_ate(&g,&sQ,&R); + PAIR_ZZZ_fexp(&g); + PAIR_ZZZ_G1mul(&U,w); + FP24_YYY_trace(&c,&g); + mpin_hash(sha,&c,&U,SK); + } + return res; +} + +/* Generate Y = H(TimeValue, xCID/xID) */ +void MPIN_ZZZ_GET_Y(int sha,int TimeValue,octet *xCID,octet *Y) +{ + BIG_XXX q,y; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,TimeValue,xCID,&H); + BIG_XXX_fromBytes(y,H.val); + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_mod(y,q); + BIG_XXX_toBytes(Y->val,y); + Y->len=PGS_ZZZ; +} + +/* One pass MPIN Client */ +int MPIN_ZZZ_CLIENT(int sha,int date,octet *ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *V,octet *U,octet *UT,octet *TP,octet *MESSAGE,int TimeValue,octet *Y) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pID; + if (date == 0) + pID = U; + else + pID = UT; + + rtn = MPIN_ZZZ_CLIENT_1(sha,date,ID,RNG,X,pin,TOKEN,V,U,UT,TP); + if (rtn != 0) + return rtn; + + OCT_joctet(&M,pID); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_CLIENT_2(X,Y,V); + if (rtn != 0) + return rtn; + + return 0; +} + +/* One pass MPIN Server */ +int MPIN_ZZZ_SERVER(int sha,int date,octet *HID,octet *HTID,octet *Y,octet *sQ,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE,int TimeValue, octet *Pa) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pU; + if (date == 0) + pU = U; + else + pU = UT; + + MPIN_ZZZ_SERVER_1(sha,date,ID,HID,HTID); + + OCT_joctet(&M,pU); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_SERVER_2(date,HID,HTID,Y,sQ,U,UT,V,E,F,Pa); + if (rtn != 0) + return rtn; + + return 0; +} + +int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa) +{ + BIG_XXX z,r; + ECP4_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + if (R!=NULL) + { + BIG_XXX_randomnum(z,r,R); + Z->len=MODBYTES_XXX; + BIG_XXX_toBytes(Z->val,z); + } + else + BIG_XXX_fromBytes(z,Z->val); + + BIG_XXX_invmodp(z,z,r); + + ECP4_ZZZ_generator(&Q); + + if (res==0) + { + PAIR_ZZZ_G2mul(&Q,z); + ECP4_ZZZ_toOctet(Pa,&Q); + } + + return res; +} \ No newline at end of file
http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto-c/blob/8d28d2c3/src/mpin256.c.in ---------------------------------------------------------------------- diff --git a/src/mpin256.c.in b/src/mpin256.c.in new file mode 100644 index 0000000..7dd261b --- /dev/null +++ b/src/mpin256.c.in @@ -0,0 +1,972 @@ +/* +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. +*/ + +/* MPIN Functions */ + +/* Version 3.0 - supports Time Permits */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include "mpin256_ZZZ.h" + + +#define ROUNDUP(a,b) ((a)-1)/(b)+1 + + +/* Special mpin hashing */ +static void mpin_hash(int sha,FP16_YYY *f, ECP_ZZZ *P,octet *w) +{ + int i; + BIG_XXX x,y; + char h[64]; + hash256 sha256; + hash512 sha512; + char t[18*MODBYTES_XXX]; // to hold 10 BIGs + int hlen=sha; + + FP_YYY_redc(x,&(f->a.a.a.a)); + BIG_XXX_toBytes(&t[0],x); + FP_YYY_redc(x,&(f->a.a.a.b)); + BIG_XXX_toBytes(&t[MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->a.a.b.a)); + BIG_XXX_toBytes(&t[2*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.a.b.b)); + BIG_XXX_toBytes(&t[3*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->a.b.a.a)); + BIG_XXX_toBytes(&t[4*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.a.b)); + BIG_XXX_toBytes(&t[5*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->a.b.b.a)); + BIG_XXX_toBytes(&t[6*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->a.b.b.b)); + BIG_XXX_toBytes(&t[7*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.a.a.a)); + BIG_XXX_toBytes(&t[8*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.a.a.b)); + BIG_XXX_toBytes(&t[9*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.a.b.a)); + BIG_XXX_toBytes(&t[10*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.a.b.b)); + BIG_XXX_toBytes(&t[11*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.b.a.a)); + BIG_XXX_toBytes(&t[12*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.a.b)); + BIG_XXX_toBytes(&t[13*MODBYTES_XXX],x); + + FP_YYY_redc(x,&(f->b.b.b.a)); + BIG_XXX_toBytes(&t[14*MODBYTES_XXX],x); + FP_YYY_redc(x,&(f->b.b.b.b)); + BIG_XXX_toBytes(&t[15*MODBYTES_XXX],x); + + ECP_ZZZ_get(x,y,P); + BIG_XXX_toBytes(&t[16*MODBYTES_XXX],x); + BIG_XXX_toBytes(&t[17*MODBYTES_XXX],y); + + OCT_empty(w); + switch (sha) + { + case SHA256: + HASH256_init(&sha256); + for (i=0; i<18*MODBYTES_XXX; i++) HASH256_process(&sha256,t[i]); + HASH256_hash(&sha256,h); + break; + case SHA384: + HASH384_init(&sha512); + for (i=0; i<18*MODBYTES_XXX; i++) HASH384_process(&sha512,t[i]); + HASH384_hash(&sha512,h); + break; + case SHA512: + HASH512_init(&sha512); + for (i=0; i<18*MODBYTES_XXX; i++) HASH512_process(&sha512,t[i]); + HASH512_hash(&sha512,h); + break; + } + + OCT_jbytes(w,h,AESKEY_ZZZ); + for (i=0; i<hlen; i++) h[i]=0; +} + +/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* maps a random u to a point on the curve */ +static void map(ECP_ZZZ *P,BIG_XXX u,int cb) +{ + BIG_XXX x,q; + + BIG_XXX_rcopy(q,Modulus_YYY); + BIG_XXX_copy(x,u); + BIG_XXX_mod(x,q); + + while (!ECP_ZZZ_setx(P,x,cb)) + { + BIG_XXX_inc(x,1); + BIG_XXX_norm(x); + } +} + +/* returns u derived from P. Random value in range 1 to return value should then be added to u */ +static int unmap(BIG_XXX u,int *cb,ECP_ZZZ *P) +{ + int s,r=0; + BIG_XXX x; + + s=ECP_ZZZ_get(x,x,P); + BIG_XXX_copy(u,x); + do + { + BIG_XXX_dec(u,1); + BIG_XXX_norm(u); + r++; + } + while (!ECP_ZZZ_setx(P,u,s)); + ECP_ZZZ_setx(P,x,s); + + *cb=s; + + return r; +} + +/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ +/* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ +/* Note that u and v are indistinguisible from random strings */ +int MPIN_ZZZ_ENCODING(csprng *RNG,octet *E) +{ + int rn,m,su,sv,res=0; + + BIG_XXX q,u,v; + ECP_ZZZ P,W; + + if (!ECP_ZZZ_fromOctet(&P,E)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_rcopy(q,Modulus_YYY); + + BIG_XXX_randomnum(u,q,RNG); + + su=RAND_byte(RNG); + if (su<0) su=-su; + su%=2; + map(&W,u,su); + ECP_ZZZ_sub(&P,&W); + + rn=unmap(v,&sv,&P); + m=RAND_byte(RNG); + if (m<0) m=-m; + m%=rn; + BIG_XXX_inc(v,m+1); + E->val[0]=su+2*sv; + BIG_XXX_toBytes(&(E->val[1]),u); + BIG_XXX_toBytes(&(E->val[PFS_ZZZ+1]),v); + } + return res; +} + +int MPIN_ZZZ_DECODING(octet *D) +{ + int su,sv; + BIG_XXX u,v; + ECP_ZZZ P,W; + int res=0; + + if ((D->val[0]&0x04)!=0) res=MPIN_INVALID_POINT; + if (res==0) + { + + BIG_XXX_fromBytes(u,&(D->val[1])); + BIG_XXX_fromBytes(v,&(D->val[PFS_ZZZ+1])); + + su=D->val[0]&1; + sv=(D->val[0]>>1)&1; + map(&W,u,su); + map(&P,v,sv); + ECP_ZZZ_add(&P,&W); + ECP_ZZZ_toOctet(D,&P); + } + + return res; +} + +/* R=R1+R2 in group G1 */ +int MPIN_ZZZ_RECOMBINE_G1(octet *R1,octet *R2,octet *R) +{ + ECP_ZZZ P,T; + int res=0; + if (res==0) + { + if (!ECP_ZZZ_fromOctet(&P,R1)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&T,R2)) res=MPIN_INVALID_POINT; + } + if (res==0) + { + ECP_ZZZ_add(&P,&T); + ECP_ZZZ_toOctet(R,&P); + } + return res; +} + +/* W=W1+W2 in group G2 */ +int MPIN_ZZZ_RECOMBINE_G2(octet *W1,octet *W2,octet *W) +{ + ECP8_ZZZ Q,T; + int res=0; + if (!ECP8_ZZZ_fromOctet(&Q,W1)) res=MPIN_INVALID_POINT; + if (!ECP8_ZZZ_fromOctet(&T,W2)) res=MPIN_INVALID_POINT; + if (res==0) + { + ECP8_ZZZ_add(&Q,&T); + ECP8_ZZZ_toOctet(W,&Q); + } + return res; +} + +/* create random secret S */ +int MPIN_ZZZ_RANDOM_GENERATE(csprng *RNG,octet* S) +{ + BIG_XXX r,s; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(s,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(s,2*AES_S); +#endif + BIG_XXX_toBytes(S->val,s); + S->len=MODBYTES_XXX; + return 0; +} + +/* Extract PIN from TOKEN for identity CID */ +int MPIN_ZZZ_EXTRACT_PIN(int sha,octet *CID,int pin,octet *TOKEN) +{ + pin%=MAXPIN; + return MPIN_ZZZ_EXTRACT_FACTOR(sha,CID,pin,PBLEN,TOKEN); +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_EXTRACT_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_sub(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P); + } + return res; +} + +/* Extract a factor < 32 bits for identity CID */ +int MPIN_ZZZ_RESTORE_FACTOR(int sha,octet *CID,int factor,int facbits,octet *TOKEN) +{ + ECP_ZZZ P,R; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + if (!ECP_ZZZ_fromOctet(&P,TOKEN)) res=MPIN_INVALID_POINT; + if (res==0) + { + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&R,&H); + + ECP_ZZZ_pinmul(&R,factor,facbits); + ECP_ZZZ_add(&P,&R); + + ECP_ZZZ_toOctet(TOKEN,&P); + } + return res; +} + +/* Implement step 2 on client side of MPin protocol - SEC=-(x+y)*SEC */ +int MPIN_ZZZ_CLIENT_2(octet *X,octet *Y,octet *SEC) +{ + BIG_XXX px,py,r; + ECP_ZZZ P; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (!ECP_ZZZ_fromOctet(&P,SEC)) res=MPIN_INVALID_POINT; + if (res==0) + { + BIG_XXX_fromBytes(px,X->val); + BIG_XXX_fromBytes(py,Y->val); + BIG_XXX_add(px,px,py); + BIG_XXX_mod(px,r); + PAIR_ZZZ_G1mul(&P,px); + ECP_ZZZ_neg(&P); + ECP_ZZZ_toOctet(SEC,&P); + } + return res; +} + +/* + W=x*H(G); + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + if type=0 W=x*G where G is point on the curve, else W=x*M(G), where M(G) is mapping of octet G to point on the curve +*/ + +int MPIN_ZZZ_GET_G1_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP_ZZZ P; + BIG_XXX r,x; + int res=0; + if (RNG!=NULL) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + if (type==0) + { + if (!ECP_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + } + else + { + ECP_ZZZ_mapit(&P,G); + } + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,x); + ECP_ZZZ_toOctet(W,&P); + } + return res; +} + +/* + if RNG == NULL then X is passed in + if RNG != NULL the X is passed out + W=x*G where G is point on the curve + if type==1 W=(x^-1)G +*/ + +int MPIN_ZZZ_GET_G2_MULTIPLE(csprng *RNG,int type,octet *X,octet *G,octet *W) +{ + ECP8_ZZZ P; + BIG_XXX r,x; + int res=0; + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + { + BIG_XXX_fromBytes(x,X->val); + if (type==1) BIG_XXX_invmodp(x,x,r); + } + + if (!ECP8_ZZZ_fromOctet(&P,G)) res=MPIN_INVALID_POINT; + + if (res==0) + { + PAIR_ZZZ_G2mul(&P,x); + ECP8_ZZZ_toOctet(W,&P); + } + return res; +} + + + +/* Client secret CST=s*H(CID) where CID is client ID and s is master secret */ +/* CID is hashed externally */ +int MPIN_ZZZ_GET_CLIENT_SECRET(octet *S,octet *CID,octet *CST) +{ + return MPIN_ZZZ_GET_G1_MULTIPLE(NULL,1,S,CID,CST); +} + +/* Implement step 1 on client side of MPin protocol */ +int MPIN_ZZZ_CLIENT_1(int sha,int date,octet *CLIENT_ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *SEC,octet *xID,octet *xCID,octet *PERMIT) +{ + BIG_XXX r,x; + ECP_ZZZ P,T,W; + int res=0; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + if (RNG!=NULL) + { + BIG_XXX_randomnum(x,r,RNG); +#ifdef AES_S + BIG_XXX_mod2m(x,2*AES_S); +#endif + X->len=MODBYTES_XXX; + BIG_XXX_toBytes(X->val,x); + } + else + BIG_XXX_fromBytes(x,X->val); + + mhashit(sha,-1,CLIENT_ID,&H); + + ECP_ZZZ_mapit(&P,&H); + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + pin%=MAXPIN; + + ECP_ZZZ_copy(&W,&P); // W=H(ID) + ECP_ZZZ_pinmul(&W,pin,PBLEN); // W=alpha.H(ID) + ECP_ZZZ_add(&T,&W); // T=Token+alpha.H(ID) = s.H(ID) + + if (date) + { + if (PERMIT!=NULL) + { + if (!ECP_ZZZ_fromOctet(&W,PERMIT)) res=MPIN_INVALID_POINT; + ECP_ZZZ_add(&T,&W); // SEC=s.H(ID)+s.H(T|ID) + } + mhashit(sha,date,&H,&H); + + ECP_ZZZ_mapit(&W,&H); + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P); // xID + PAIR_ZZZ_G1mul(&W,x); // W=x.H(T|ID) + ECP_ZZZ_add(&P,&W); + } + else + { + ECP_ZZZ_add(&P,&W); + PAIR_ZZZ_G1mul(&P,x); + } + if (xCID!=NULL) ECP_ZZZ_toOctet(xCID,&P); // U + } + else + { + if (xID!=NULL) + { + PAIR_ZZZ_G1mul(&P,x); // P=x.H(ID) + ECP_ZZZ_toOctet(xID,&P); // xID + } + } + } + + if (res==0) + ECP_ZZZ_toOctet(SEC,&T); // V + + return res; +} + +/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ +int MPIN_ZZZ_GET_SERVER_SECRET(octet *S,octet *SST) +{ + BIG_XXX r,s; + ECP8_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + ECP8_ZZZ_generator(&Q); + + if (res==0) + { + BIG_XXX_fromBytes(s,S->val); + PAIR_ZZZ_G2mul(&Q,s); + ECP8_ZZZ_toOctet(SST,&Q); + } + + return res; +} + + +/* Time Permit CTT=s*H(date|H(CID)) where s is master secret */ +int MPIN_ZZZ_GET_CLIENT_PERMIT(int sha,int date,octet *S,octet *CID,octet *CTT) +{ + BIG_XXX s; + ECP_ZZZ P; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,date,CID,&H); + + ECP_ZZZ_mapit(&P,&H); + + BIG_XXX_fromBytes(s,S->val); + + PAIR_ZZZ_G1mul(&P,s); + ECP_ZZZ_toOctet(CTT,&P); + return 0; +} + +// if date=0 only use HID, set HCID=NULL +// if date and PE, use HID and HCID + +/* Outputs H(CID) and H(CID)+H(T|H(CID)) for time permits. If no time permits set HTID=NULL */ +void MPIN_ZZZ_SERVER_1(int sha,int date,octet *CID,octet *HID,octet *HTID) +{ + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + ECP_ZZZ P,R; + +#ifdef USE_ANONYMOUS + ECP_ZZZ_mapit(&P,CID); +#else + mhashit(sha,-1,CID,&H); + ECP_ZZZ_mapit(&P,&H); +#endif + + ECP_ZZZ_toOctet(HID,&P); // new + + if (date) + { +#ifdef USE_ANONYMOUS + mhashit(sha,date,CID,&H); +#else + mhashit(sha,date,&H,&H); +#endif + ECP_ZZZ_mapit(&R,&H); + ECP_ZZZ_add(&P,&R); + ECP_ZZZ_toOctet(HTID,&P); + } +} + +/* Implement M-Pin on server side */ +int MPIN_ZZZ_SERVER_2(int date,octet *HID,octet *HTID,octet *Y,octet *SST,octet *xID,octet *xCID,octet *mSEC,octet *E,octet *F,octet *Pa) +{ + BIG_XXX px,py,y; + FP48_YYY g; + ECP8_ZZZ Q,sQ; + ECP_ZZZ P,R; + int res=0; + + ECP8_ZZZ_generator(&Q); + + // key-escrow less scheme: use Pa instead of Q in pairing computation + // Q left for backward compatiblity + if (Pa!=NULL) + { + if (!ECP8_ZZZ_fromOctet(&Q, Pa)) res=MPIN_INVALID_POINT; + } + + + if (res==0) + { + if (!ECP8_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + } + + if (res==0) + { + if (date) + { + BIG_XXX_fromBytes(px,&(xCID->val[1])); + BIG_XXX_fromBytes(py,&(xCID->val[PFS_ZZZ+1])); + } + else + { + BIG_XXX_fromBytes(px,&(xID->val[1])); + BIG_XXX_fromBytes(py,&(xID->val[PFS_ZZZ+1])); + } + if (!ECP_ZZZ_set(&R,px,py)) res=MPIN_INVALID_POINT; // x(A+AT) + } + if (res==0) + { + BIG_XXX_fromBytes(y,Y->val); + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HTID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + } + } + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // y(A+AT) + ECP_ZZZ_add(&P,&R); // x(A+AT)+y(A+T) + ECP_ZZZ_affine(&P); + if (!ECP_ZZZ_fromOctet(&R,mSEC)) res=MPIN_INVALID_POINT; // V + } + if (res==0) + { + + PAIR_ZZZ_double_ate(&g,&Q,&R,&sQ,&P); + PAIR_ZZZ_fexp(&g); + + if (!FP48_YYY_isunity(&g)) + { + if (HID!=NULL && xID!=NULL && E!=NULL && F !=NULL) + { + /* xID is set to NULL if there is no way to calculate PIN error */ + FP48_YYY_toOctet(E,&g); + + /* Note error is in the PIN, not in the time permit! Hence the need to exclude Time Permit from this check */ + + if (date) + { + if (!ECP_ZZZ_fromOctet(&P,HID)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,xID)) res=MPIN_INVALID_POINT; // U + + if (res==0) + { + PAIR_ZZZ_G1mul(&P,y); // yA + ECP_ZZZ_add(&P,&R); // yA+xA + ECP_ZZZ_affine(&P); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP48_YYY_toOctet(F,&g); + } + } + res=MPIN_BAD_PIN; + } + } + + return res; +} + +#if MAXPIN==10000 +#define MR_TS 10 /* 2^10/10 approx = sqrt(MAXPIN) */ +#define TRAP 200 /* 2*sqrt(MAXPIN) */ +#endif + +#if MAXPIN==1000000 +#define MR_TS 14 +#define TRAP 2000 +#endif + +/* Pollards kangaroos used to return PIN error */ +int MPIN_ZZZ_KANGAROO(octet *E,octet *F) +{ + int i,j,m,s,dn,dm,steps; + int distance[MR_TS]; + FP48_YYY ge,gf,t,table[MR_TS]; + int res=0; + + FP48_YYY_fromOctet(&ge,E); + FP48_YYY_fromOctet(&gf,F); + + FP48_YYY_copy(&t,&gf); + + for (s=1,m=0; m<MR_TS; m++) + { + distance[m]=s; + FP48_YYY_copy(&table[m],&t); + s*=2; + FP48_YYY_usqr(&t,&t); + FP48_YYY_reduce(&t); + } + + FP48_YYY_one(&t); + + for (dn=0,j=0; j<TRAP; j++) + { + i=t.a.a.a.a.a.g[0]%MR_TS; + + FP48_YYY_mul(&t,&table[i]); + FP48_YYY_reduce(&t); + dn+=distance[i]; + } + + FP48_YYY_conj(&gf,&t); + steps=0; + dm=0; + while (dm-dn<MAXPIN) + { + steps++; + if (steps>4*TRAP) break; + + i=ge.a.a.a.a.a.g[0]%MR_TS; + + FP48_YYY_mul(&ge,&table[i]); + FP48_YYY_reduce(&ge); + dm+=distance[i]; + if (FP48_YYY_equals(&ge,&t)) + { + res=dm-dn; + break; + } + if (FP48_YYY_equals(&ge,&gf)) + { + res=dn-dm; + break; + } + } + if (steps>4*TRAP || dm-dn>=MAXPIN) + { + res=0; /* Trap Failed - probable invalid token */ + } + + return res; +} + +/* Functions to support M-Pin Full */ + +int MPIN_ZZZ_PRECOMPUTE(octet *TOKEN,octet *CID,octet *CP,octet *G1,octet *G2) +{ + ECP_ZZZ P,T; + ECP8_ZZZ Q; + FP48_YYY g; + int res=0; + + if (!ECP_ZZZ_fromOctet(&T,TOKEN)) res=MPIN_INVALID_POINT; + + if (res==0) + { + ECP_ZZZ_mapit(&P,CID); + if (CP!=NULL) + { + if (!ECP8_ZZZ_fromOctet(&Q,CP)) res=MPIN_INVALID_POINT; + } + else + { + ECP8_ZZZ_generator(&Q); + } + } + if (res==0) + { + PAIR_ZZZ_ate(&g,&Q,&T); + PAIR_ZZZ_fexp(&g); + + FP48_YYY_toOctet(G1,&g); + if (G2!=NULL) + { + PAIR_ZZZ_ate(&g,&Q,&P); + PAIR_ZZZ_fexp(&g); + FP48_YYY_toOctet(G2,&g); + } + } + return res; +} + +/* calculate common key on client side */ +/* wCID = w.(A+AT) */ +int MPIN_ZZZ_CLIENT_KEY(int sha,octet *G1,octet *G2,int pin,octet *R,octet *X,octet *H,octet *wCID,octet *CK) +{ + FP48_YYY g1,g2; + FP16_YYY c; + + ECP_ZZZ W; + int res=0; + BIG_XXX r,z,x,h; + + FP48_YYY_fromOctet(&g1,G1); + FP48_YYY_fromOctet(&g2,G2); + BIG_XXX_fromBytes(z,R->val); + BIG_XXX_fromBytes(x,X->val); + BIG_XXX_fromBytes(h,H->val); + + if (!ECP_ZZZ_fromOctet(&W,wCID)) res=MPIN_INVALID_POINT; + + if (res==0) + { + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + BIG_XXX_add(z,z,h); // new + BIG_XXX_mod(z,r); + + FP48_YYY_pinpow(&g2,pin,PBLEN); + FP48_YYY_mul(&g1,&g2); + + PAIR_ZZZ_G1mul(&W,x); + + FP48_YYY_compow(&c,&g1,z,r); + mpin_hash(sha,&c,&W,CK); + + } + return res; +} + +/* calculate common key on server side */ +/* Z=r.A - no time permits involved */ + +int MPIN_ZZZ_SERVER_KEY(int sha,octet *Z,octet *SST,octet *W,octet *H,octet *HID,octet *xID,octet *xCID,octet *SK) +{ + int res=0; + FP48_YYY g; + FP16_YYY c; + ECP_ZZZ R,U,A; + ECP8_ZZZ sQ; + BIG_XXX w,h; + + if (!ECP8_ZZZ_fromOctet(&sQ,SST)) res=MPIN_INVALID_POINT; + if (!ECP_ZZZ_fromOctet(&R,Z)) res=MPIN_INVALID_POINT; + + + if (!ECP_ZZZ_fromOctet(&A,HID)) res=MPIN_INVALID_POINT; + + // new + if (xCID!=NULL) + { + if (!ECP_ZZZ_fromOctet(&U,xCID)) res=MPIN_INVALID_POINT; + } + else + { + if (!ECP_ZZZ_fromOctet(&U,xID)) res=MPIN_INVALID_POINT; + } + BIG_XXX_fromBytes(w,W->val); + BIG_XXX_fromBytes(h,H->val); + + + PAIR_ZZZ_ate(&g,&sQ,&A); + PAIR_ZZZ_fexp(&g); + + if (res==0) + { + PAIR_ZZZ_G1mul(&A,h); + ECP_ZZZ_add(&R,&A); // new + ECP_ZZZ_affine(&R); + PAIR_ZZZ_ate(&g,&sQ,&R); + PAIR_ZZZ_fexp(&g); + PAIR_ZZZ_G1mul(&U,w); + FP48_YYY_trace(&c,&g); + mpin_hash(sha,&c,&U,SK); + } + return res; +} + +/* Generate Y = H(TimeValue, xCID/xID) */ +void MPIN_ZZZ_GET_Y(int sha,int TimeValue,octet *xCID,octet *Y) +{ + BIG_XXX q,y; + char h[MODBYTES_XXX]; + octet H= {0,sizeof(h),h}; + + mhashit(sha,TimeValue,xCID,&H); + BIG_XXX_fromBytes(y,H.val); + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_mod(y,q); + BIG_XXX_toBytes(Y->val,y); + Y->len=PGS_ZZZ; +} + +/* One pass MPIN Client */ +int MPIN_ZZZ_CLIENT(int sha,int date,octet *ID,csprng *RNG,octet *X,int pin,octet *TOKEN,octet *V,octet *U,octet *UT,octet *TP,octet *MESSAGE,int TimeValue,octet *Y) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pID; + if (date == 0) + pID = U; + else + pID = UT; + + rtn = MPIN_ZZZ_CLIENT_1(sha,date,ID,RNG,X,pin,TOKEN,V,U,UT,TP); + if (rtn != 0) + return rtn; + + OCT_joctet(&M,pID); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_CLIENT_2(X,Y,V); + if (rtn != 0) + return rtn; + + return 0; +} + +/* One pass MPIN Server */ +int MPIN_ZZZ_SERVER(int sha,int date,octet *HID,octet *HTID,octet *Y,octet *sQ,octet *U,octet *UT,octet *V,octet *E,octet *F,octet *ID,octet *MESSAGE,int TimeValue, octet *Pa) +{ + int rtn=0; + char m[M_SIZE_ZZZ]; + octet M= {0,sizeof(m),m}; + + octet *pU; + if (date == 0) + pU = U; + else + pU = UT; + + MPIN_ZZZ_SERVER_1(sha,date,ID,HID,HTID); + + OCT_joctet(&M,pU); + if (MESSAGE!=NULL) + { + OCT_joctet(&M,MESSAGE); + } + + MPIN_ZZZ_GET_Y(sha,TimeValue,&M,Y); + + rtn = MPIN_ZZZ_SERVER_2(date,HID,HTID,Y,sQ,U,UT,V,E,F,Pa); + if (rtn != 0) + return rtn; + + return 0; +} + +int MPIN_ZZZ_GET_DVS_KEYPAIR(csprng *R,octet *Z,octet *Pa) +{ + BIG_XXX z,r; + ECP8_ZZZ Q; + int res=0; + + BIG_XXX_rcopy(r,CURVE_Order_ZZZ); + + if (R!=NULL) + { + BIG_XXX_randomnum(z,r,R); + Z->len=MODBYTES_XXX; + BIG_XXX_toBytes(Z->val,z); + } + else + BIG_XXX_fromBytes(z,Z->val); + + BIG_XXX_invmodp(z,z,r); + + ECP8_ZZZ_generator(&Q); + + if (res==0) + { + PAIR_ZZZ_G2mul(&Q,z); + ECP8_ZZZ_toOctet(Pa,&Q); + } + + return res; +} http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto-c/blob/8d28d2c3/src/oct.c ---------------------------------------------------------------------- diff --git a/src/oct.c b/src/oct.c new file mode 100644 index 0000000..abaece3 --- /dev/null +++ b/src/oct.c @@ -0,0 +1,424 @@ +/* +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. +*/ + +/*** Basic Octet string maintainance routines ***/ +/* SU=m, m is Stack Usage */ + +#include <string.h> +#include "amcl.h" + +/* Output an octet string (Debug Only) */ + +/* SU= 16 */ +/* output octet */ +void OCT_output(octet *w) +{ + int i; + unsigned char ch; + for (i=0; i<w->len; i++) + { + ch=w->val[i]; + printf("%02x",ch); + } + printf("\n"); +} + +/* SU= 16 */ +void OCT_output_string(octet *w) +{ + int i; + unsigned char ch; + for (i=0; i<w->len; i++) + { + ch=w->val[i]; + printf("%c",ch); + } +} + +/* Convert C string to octet format - truncates if no room */ +void OCT_jstring(octet *y,char *s) +{ + int i,j; + i=y->len; + j=0; + while (s[j]!=0 && i<y->max) + { + y->val[i]=s[j]; + y->len++; + i++; + j++; + } +} + +/* compare 2 octet strings. + * If x==y return TRUE, else return FALSE */ +/* SU= 8 */ +int OCT_comp(octet *x,octet *y) +{ + int i; + if (x->len>y->len) return 0; + if (x->len<y->len) return 0; + for (i=0; i<x->len; i++) + { + if (x->val[i]!=y->val[i]) return 0; + } + return 1; +} + +/* check are first n bytes the same */ + +int OCT_ncomp(octet *x,octet *y,int n) +{ + int i; + if (n>y->len || n>x->len) return 0; + for (i=0; i<n; i++) + { + if (x->val[i]!=y->val[i]) return 0; + } + return 1; +} + +/* Shift octet to the left by n bytes. Leftmost bytes disappear */ +void OCT_shl(octet *x,int n) +{ + int i; + if (n>=x->len) + { + x->len=0; + return; + } + x->len-=n; + for (i=0; i<x->len; i++) + x->val[i]=x->val[i+n]; +} + +/* Append binary string to octet - truncates if no room */ +/* SU= 12 */ +void OCT_jbytes(octet *y,char *b,int len) +{ + int i,j; + i=y->len; + for (j=0; j<len && i<y->max; j++) + { + y->val[i]=b[j]; + y->len++; + i++; + } +} + +/* Concatenates two octet strings */ +/* SU= 8 */ +void OCT_joctet(octet *y,octet *x) +{ + /* y=y || x */ + int i,j; + if (x==NULL) return; + + for (i=0; i<x->len; i++) + { + j=y->len+i; + if (j>=y->max) + { + y->len=y->max; + return; + } + y->val[j]=x->val[i]; + } + y->len+=x->len; +} + +/* Append byte to octet rep times */ +/* SU= 8 */ +void OCT_jbyte(octet *y,int ch,int rep) +{ + int i,j; + i=y->len; + for (j=0; j<rep && i<y->max; j++) + { + y->val[i]=ch; + y->len++; + i++; + } +} + +/* XOR common bytes of x with y */ +/* SU= 8 */ +void OCT_xor(octet *y,octet *x) +{ + /* xor first x->len bytes of y */ + + int i; + for (i=0; i<x->len && i<y->len; i++) + { + y->val[i]^=x->val[i]; + } +} + +/* clear an octet */ +void OCT_empty(octet *w) +{ + w->len=0; +} + +/* Kill an octet string - Zeroise it for security */ +void OCT_clear(octet *w) +{ + int i; + for (i=0; i<w->max; i++) w->val[i]=0; + w->len=0; +} + +/* appends int x of length len bytes to OCTET string */ +/* SU= 8 */ +void OCT_jint(octet *y,int x,int len) +{ + int i,n; + n=y->len+len; + if (n>y->max || len<=0) return; + for (i=y->len; i<n; i++) y->val[i]=0; + y->len=n; + + i=y->len; + while (x>0 && i>0) + { + i--; + y->val[i]=x%256; + x/=256; + } +} + +/* Pad an octet to a given length */ +/* SU= 8 */ +int OCT_pad(octet *w,int n) +{ + int i,d; + if (w->len>n || n>w->max) return 0; + if (n==w->len) return 1; + d=n-w->len; + for (i=n-1; i>=d; i--) + w->val[i]=w->val[i-d]; + for (i=d-1; i>=0; i--) + w->val[i]=0; + w->len=n; + return 1; +} + + +/* Convert an octet string to base64 string */ +/* SU= 56 */ +void OCT_tobase64(char *b,octet *w) +{ + int i,j,k,rem,last; + int c,ch[4]; + unsigned char ptr[3]; + rem=w->len%3; + j=k=0; + last=4; + while (j<w->len) + { + for (i=0; i<3; i++) + { + if (j<w->len) ptr[i]=w->val[j++]; + else + { + ptr[i]=0; + last--; + } + } + ch[0]=(ptr[0]>>2)&0x3f; + ch[1]=((ptr[0]<<4)|(ptr[1]>>4))&0x3f; + ch[2]=((ptr[1]<<2)|(ptr[2]>>6))&0x3f; + ch[3]=ptr[2]&0x3f; + for (i=0; i<last; i++) + { + c=ch[i]; + if (c<26) c+=65; + if (c>=26 && c<52) c+=71; + if (c>=52 && c<62) c-=4; + if (c==62) c='+'; + if (c==63) c='/'; + b[k++]=c; + } + } + if (rem>0) for (i=rem; i<3; i++) b[k++]='='; + b[k]='\0'; /* dangerous! */ +} + +/* SU= 56 */ +void OCT_frombase64(octet *w,char *b) +{ + int i,j,k,pads,len=(int)strlen(b); + int c,ch[4],ptr[3]; + j=k=0; + while (j<len && k<w->max) + { + pads=0; + for (i=0; i<4; i++) + { + c=80+b[j++]; + if (c<=112) continue; /* ignore white space */ + if (c>144 && c<171) c-=145; + if (c>176 && c<203) c-=151; + if (c>127 && c<138) c-=76; + if (c==123) c=62; + if (c==127) c=63; + if (c==141) + { + pads++; /* ignore pads '=' */ + continue; + } + ch[i]=c; + } + ptr[0]=(ch[0]<<2)|(ch[1]>>4); + ptr[1]=(ch[1]<<4)|(ch[2]>>2); + ptr[2]=(ch[2]<<6)|ch[3]; + for (i=0; i<3-pads && k<w->max; i++) + { + /* don't put in leading zeros */ + w->val[k++]=ptr[i]; + } + + } + w->len=k; +} + +/* copy an octet string - truncates if no room */ +/* SU= 16 */ +void OCT_copy(octet *y,octet *x) +{ + int i; + OCT_clear(y); + y->len=x->len; + if (y->len>y->max) y->len=y->max; + + for (i=0; i<y->len; i++) + y->val[i]=x->val[i]; +} + +/* XOR m with all of x */ +void OCT_xorbyte(octet *x,int m) +{ + int i; + for (i=0; i<x->len; i++) x->val[i]^=m; +} + +/* truncates x to n bytes and places the rest in y (if y is not NULL) */ +/* SU= 8 */ +void OCT_chop(octet *x,octet *y,int n) +{ + int i; + if (n>=x->len) + { + if (y!=NULL) y->len=0; + return; + } + if (y!=NULL) y->len=x->len-n; + x->len=n; + + if (y!=NULL) + { + for (i=0; i<y->len && i<y->max; i++) y->val[i]=x->val[i+n]; + } +} + +/* set x to len random bytes */ +void OCT_rand(octet *x,csprng *RNG,int len) +{ + int i; + if (len>x->max) len=x->max; + x->len=len; + + for (i=0; i<len; i++) x->val[i]=RAND_byte(RNG); +} + +/* Convert an octet to a hex string */ +void OCT_toHex(octet *src,char *dst) +{ + int i; + unsigned char ch; + for (i=0; i<src->len; i++) + { + ch=src->val[i]; + sprintf(&dst[i*2],"%02x", ch); + } +} + +static int char2int(char input) +{ + if(input >= '0' && input <= '9') + return input - '0'; + if(input >= 'A' && input <= 'F') + return input - 'A' + 10; + if(input >= 'a' && input <= 'f') + return input - 'a' + 10; + return 0; +} + +/* Convert from a hex string */ +void OCT_fromHex(octet *dst,char *src) +{ + int i=0; + int j=0; + OCT_clear(dst); + + while(src[j]!=0) + { + dst->val[i++] = char2int(src[j])*16 + char2int(src[j+1]); + j += 2; + } + dst->len=i; +} + + +/* Convert an octet to a string */ +void OCT_toStr(octet *src,char *dst) +{ + int i; + unsigned char ch; + for (i=0; i<src->len; i++) + { + ch=src->val[i]; + sprintf(&dst[i],"%c", ch); + } +} + +/* Test program +#include <stdio.h> +#include "amcl.h" + +char test[]="abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"; + +int main() +{ + char gm[100],gn[100],t[100]; + octet m={0,sizeof(gm),gm}; + octet n={0,sizeof(gn),gn}; + + OCT_jbytes(&m,test,strlen(test)); + OCT_output(&m); + + OCT_tobase64(t,&m); + printf(t); printf("\n"); + + OCT_frombase64(&n,t); + OCT_output(&n); + + return 0; +} +*/ http://git-wip-us.apache.org/repos/asf/incubator-milagro-crypto-c/blob/8d28d2c3/src/pair.c.in ---------------------------------------------------------------------- diff --git a/src/pair.c.in b/src/pair.c.in new file mode 100644 index 0000000..26b479a --- /dev/null +++ b/src/pair.c.in @@ -0,0 +1,781 @@ +/* +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 "pair_ZZZ.h" + +/* Line function */ +static void PAIR_ZZZ_line(FP12_YYY *v,ECP2_ZZZ *A,ECP2_ZZZ *B,FP_YYY *Qx,FP_YYY *Qy) +{ + FP2_YYY X1,Y1,T1,T2; + FP2_YYY XX,YY,ZZ,YZ; + FP4_YYY a,b,c; + + if (A==B) + { + /* doubling */ + FP2_YYY_copy(&XX,&(A->x)); //FP2 XX=new FP2(A.getx()); //X + FP2_YYY_copy(&YY,&(A->y)); //FP2 YY=new FP2(A.gety()); //Y + FP2_YYY_copy(&ZZ,&(A->z)); //FP2 ZZ=new FP2(A.getz()); //Z + + + FP2_YYY_copy(&YZ,&YY); //FP2 YZ=new FP2(YY); //Y + FP2_YYY_mul(&YZ,&YZ,&ZZ); //YZ.mul(ZZ); //YZ + FP2_YYY_sqr(&XX,&XX); //XX.sqr(); //X^2 + FP2_YYY_sqr(&YY,&YY); //YY.sqr(); //Y^2 + FP2_YYY_sqr(&ZZ,&ZZ); //ZZ.sqr(); //Z^2 + + FP2_YYY_imul(&YZ,&YZ,4); //YZ.imul(4); + FP2_YYY_neg(&YZ,&YZ); //YZ.neg(); + FP2_YYY_norm(&YZ); //YZ.norm(); //-4YZ + + FP2_YYY_imul(&XX,&XX,6); //6X^2 + FP2_YYY_pmul(&XX,&XX,Qx); //6X^2.Xs + + FP2_YYY_imul(&ZZ,&ZZ,3*CURVE_B_I_ZZZ); //3Bz^2 + + FP2_YYY_pmul(&YZ,&YZ,Qy); //-4YZ.Ys + +#if SEXTIC_TWIST_ZZZ==D_TYPE + FP2_YYY_div_ip2(&ZZ); //6(b/i)z^2 +#endif +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP2_YYY_mul_ip(&ZZ); + FP2_YYY_add(&ZZ,&ZZ,&ZZ); // 6biz^2 + FP2_YYY_mul_ip(&YZ); + FP2_YYY_norm(&YZ); +#endif + FP2_YYY_norm(&ZZ); // 6bi.Z^2 + + FP2_YYY_add(&YY,&YY,&YY); // 2y^2 + FP2_YYY_sub(&ZZ,&ZZ,&YY); // + FP2_YYY_norm(&ZZ); // 6b.Z^2-2Y^2 + + FP4_YYY_from_FP2s(&a,&YZ,&ZZ); // -4YZ.Ys | 6b.Z^2-2Y^2 | 6X^2.Xs +#if SEXTIC_TWIST_ZZZ==D_TYPE + FP4_YYY_from_FP2(&b,&XX); + FP4_YYY_zero(&c); +#endif +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP4_YYY_zero(&b); + FP4_YYY_from_FP2H(&c,&XX); +#endif + + ECP2_ZZZ_dbl(A); //A.dbl(); + } + else + { + /* addition */ + + FP2_YYY_copy(&X1,&(A->x)); //FP2 X1=new FP2(A.getx()); // X1 + FP2_YYY_copy(&Y1,&(A->y)); //FP2 Y1=new FP2(A.gety()); // Y1 + FP2_YYY_copy(&T1,&(A->z)); //FP2 T1=new FP2(A.getz()); // Z1 + + FP2_YYY_copy(&T2,&T1); //FP2 T2=new FP2(A.getz()); // Z1 + + FP2_YYY_mul(&T1,&T1,&(B->y)); //T1.mul(B.gety()); // T1=Z1.Y2 + FP2_YYY_mul(&T2,&T2,&(B->x)); //T2.mul(B.getx()); // T2=Z1.X2 + + FP2_YYY_sub(&X1,&X1,&T2); //X1.sub(T2); + FP2_YYY_norm(&X1); //X1.norm(); // X1=X1-Z1.X2 + FP2_YYY_sub(&Y1,&Y1,&T1); //Y1.sub(T1); + FP2_YYY_norm(&Y1); //Y1.norm(); // Y1=Y1-Z1.Y2 + + FP2_YYY_copy(&T1,&X1); //T1.copy(X1); // T1=X1-Z1.X2 + + FP2_YYY_pmul(&X1,&X1,Qy); //X1.pmul(Qy); // X1=(X1-Z1.X2).Ys +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP2_YYY_mul_ip(&X1); + FP2_YYY_norm(&X1); +#endif + + FP2_YYY_mul(&T1,&T1,&(B->y)); //T1.mul(B.gety()); // T1=(X1-Z1.X2).Y2 + + FP2_YYY_copy(&T2,&Y1); //T2.copy(Y1); // T2=Y1-Z1.Y2 + FP2_YYY_mul(&T2,&T2,&(B->x)); //T2.mul(B.getx()); // T2=(Y1-Z1.Y2).X2 + FP2_YYY_sub(&T2,&T2,&T1); //T2.sub(T1); + FP2_YYY_norm(&T2); //T2.norm(); // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 + FP2_YYY_pmul(&Y1,&Y1,Qx); //Y1.pmul(Qx); + FP2_YYY_neg(&Y1,&Y1); //Y1.neg(); + FP2_YYY_norm(&Y1); //Y1.norm(); // Y1=-(Y1-Z1.Y2).Xs + + FP4_YYY_from_FP2s(&a,&X1,&T2); // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs +#if SEXTIC_TWIST_ZZZ==D_TYPE + FP4_YYY_from_FP2(&b,&Y1); //b=new FP4(Y1); + FP4_YYY_zero(&c); +#endif +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP4_YYY_zero(&b); + FP4_YYY_from_FP2H(&c,&Y1); //b=new FP4(Y1); +#endif + ECP2_ZZZ_add(A,B); //A.add(B); + } + + FP12_YYY_from_FP4s(v,&a,&b,&c); +} + +/* Optimal R-ate pairing r=e(P,Q) */ +void PAIR_ZZZ_ate(FP12_YYY *r,ECP2_ZZZ *P,ECP_ZZZ *Q) +{ + + BIG_XXX x,n,n3; + FP_YYY Qx,Qy; + int i,nb,bt; + ECP2_ZZZ A; + FP12_YYY lv; +#if PAIRING_FRIENDLY_ZZZ==BN + ECP2_ZZZ KA; + FP2_YYY X; + + FP_YYY_rcopy(&Qx,Fra_YYY); + FP_YYY_rcopy(&Qy,Frb_YYY); + FP2_YYY_from_FPs(&X,&Qx,&Qy); + +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP2_YYY_inv(&X,&X); + FP2_YYY_norm(&X); +#endif +#endif + + BIG_XXX_rcopy(x,CURVE_Bnx_ZZZ); + +#if PAIRING_FRIENDLY_ZZZ==BN + BIG_XXX_pmul(n,x,6); +#if SIGN_OF_X_ZZZ==POSITIVEX + BIG_XXX_inc(n,2); +#else + BIG_XXX_dec(n,2); +#endif +#else + BIG_XXX_copy(n,x); +#endif + + BIG_XXX_norm(n); + BIG_XXX_pmul(n3,n,3); + BIG_XXX_norm(n3); + + FP_YYY_copy(&Qx,&(Q->x)); + FP_YYY_copy(&Qy,&(Q->y)); + + ECP2_ZZZ_copy(&A,P); + FP12_YYY_one(r); + nb=BIG_XXX_nbits(n3); //n + + /* Main Miller Loop */ + for (i=nb-2; i>=1; i--) //0 + { + FP12_YYY_sqr(r,r); + PAIR_ZZZ_line(&lv,&A,&A,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + bt=BIG_XXX_bit(n3,i)-BIG_XXX_bit(n,i); + if (bt==1) + { + + PAIR_ZZZ_line(&lv,&A,P,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + } + if (bt==-1) + { + ECP2_ZZZ_neg(P); + PAIR_ZZZ_line(&lv,&A,P,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_neg(P); + } + } + +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(r,r); +#endif + + /* R-ate fixup required for BN curves */ +#if PAIRING_FRIENDLY_ZZZ==BN + ECP2_ZZZ_copy(&KA,P); + ECP2_ZZZ_frob(&KA,&X); +#if SIGN_OF_X_ZZZ==NEGATIVEX + ECP2_ZZZ_neg(&A); +#endif + PAIR_ZZZ_line(&lv,&A,&KA,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_frob(&KA,&X); + ECP2_ZZZ_neg(&KA); + PAIR_ZZZ_line(&lv,&A,&KA,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); +#endif +} + +/* Optimal R-ate double pairing e(P,Q).e(R,S) */ +void PAIR_ZZZ_double_ate(FP12_YYY *r,ECP2_ZZZ *P,ECP_ZZZ *Q,ECP2_ZZZ *R,ECP_ZZZ *S) +{ + BIG_XXX x,n,n3; + FP_YYY Qx,Qy,Sx,Sy; + int i,nb,bt; + ECP2_ZZZ A,B; + FP12_YYY lv; +#if PAIRING_FRIENDLY_ZZZ==BN + FP2_YYY X; + ECP2_ZZZ K; + + FP_YYY_rcopy(&Qx,Fra_YYY); + FP_YYY_rcopy(&Qy,Frb_YYY); + FP2_YYY_from_FPs(&X,&Qx,&Qy); + +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP2_YYY_inv(&X,&X); + FP2_YYY_norm(&X); +#endif +#endif + + BIG_XXX_rcopy(x,CURVE_Bnx_ZZZ); + +#if PAIRING_FRIENDLY_ZZZ==BN + BIG_XXX_pmul(n,x,6); +#if SIGN_OF_X_ZZZ==POSITIVEX + BIG_XXX_inc(n,2); +#else + BIG_XXX_dec(n,2); +#endif +#else + BIG_XXX_copy(n,x); +#endif + + BIG_XXX_norm(n); + BIG_XXX_pmul(n3,n,3); + BIG_XXX_norm(n3); + + FP_YYY_copy(&Qx,&(Q->x)); + FP_YYY_copy(&Qy,&(Q->y)); + + FP_YYY_copy(&Sx,&(S->x)); + FP_YYY_copy(&Sy,&(S->y)); + + ECP2_ZZZ_copy(&A,P); + ECP2_ZZZ_copy(&B,R); + FP12_YYY_one(r); + nb=BIG_XXX_nbits(n3); + + /* Main Miller Loop */ + for (i=nb-2; i>=1; i--) + { + FP12_YYY_sqr(r,r); + PAIR_ZZZ_line(&lv,&A,&A,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + + PAIR_ZZZ_line(&lv,&B,&B,&Sx,&Sy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + + bt=BIG_XXX_bit(n3,i)-BIG_XXX_bit(n,i); + if (bt==1) + { + PAIR_ZZZ_line(&lv,&A,P,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + + PAIR_ZZZ_line(&lv,&B,R,&Sx,&Sy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + } + + if (bt==-1) + { + ECP2_ZZZ_neg(P); + PAIR_ZZZ_line(&lv,&A,P,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_neg(P); + + ECP2_ZZZ_neg(R); + PAIR_ZZZ_line(&lv,&B,R,&Sx,&Sy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_neg(R); + } + } + + /* R-ate fixup required for BN curves */ + +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(r,r); +#endif + +#if PAIRING_FRIENDLY_ZZZ==BN + +#if SIGN_OF_X_ZZZ==NEGATIVEX + ECP2_ZZZ_neg(&A); + ECP2_ZZZ_neg(&B); +#endif + + ECP2_ZZZ_copy(&K,P); + ECP2_ZZZ_frob(&K,&X); + + PAIR_ZZZ_line(&lv,&A,&K,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_frob(&K,&X); + ECP2_ZZZ_neg(&K); + PAIR_ZZZ_line(&lv,&A,&K,&Qx,&Qy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + + ECP2_ZZZ_copy(&K,R); + ECP2_ZZZ_frob(&K,&X); + + PAIR_ZZZ_line(&lv,&B,&K,&Sx,&Sy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + ECP2_ZZZ_frob(&K,&X); + ECP2_ZZZ_neg(&K); + PAIR_ZZZ_line(&lv,&B,&K,&Sx,&Sy); + FP12_YYY_smul(r,&lv,SEXTIC_TWIST_ZZZ); + +#endif +} + +/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */ +void PAIR_ZZZ_fexp(FP12_YYY *r) +{ + FP2_YYY X; + BIG_XXX x; + FP_YYY a,b; + FP12_YYY t0,y0,y1,y2,y3; + + BIG_XXX_rcopy(x,CURVE_Bnx_ZZZ); + FP_YYY_rcopy(&a,Fra_YYY); + FP_YYY_rcopy(&b,Frb_YYY); + FP2_YYY_from_FPs(&X,&a,&b); + + /* Easy part of final exp */ + + FP12_YYY_inv(&t0,r); + FP12_YYY_conj(r,r); + + FP12_YYY_mul(r,&t0); + FP12_YYY_copy(&t0,r); + + FP12_YYY_frob(r,&X); + FP12_YYY_frob(r,&X); + FP12_YYY_mul(r,&t0); + + /* Hard part of final exp - see Duquesne & Ghamman eprint 2015/192.pdf */ +#if PAIRING_FRIENDLY_ZZZ==BN + FP12_YYY_pow(&t0,r,x); // t0=f^-u +#if SIGN_OF_X_ZZZ==POSITIVEX + FP12_YYY_conj(&t0,&t0); +#endif + FP12_YYY_usqr(&y3,&t0); // y3=t0^2 + FP12_YYY_copy(&y0,&t0); + FP12_YYY_mul(&y0,&y3); // y0=t0*y3 + FP12_YYY_copy(&y2,&y3); + FP12_YYY_frob(&y2,&X); // y2=y3^p + FP12_YYY_mul(&y2,&y3); //y2=y2*y3 + FP12_YYY_usqr(&y2,&y2); //y2=y2^2 + FP12_YYY_mul(&y2,&y3); // y2=y2*y3 + + FP12_YYY_pow(&t0,&y0,x); //t0=y0^-u +#if SIGN_OF_X_ZZZ==POSITIVEX + FP12_YYY_conj(&t0,&t0); +#endif + FP12_YYY_conj(&y0,r); //y0=~r + FP12_YYY_copy(&y1,&t0); + FP12_YYY_frob(&y1,&X); + FP12_YYY_frob(&y1,&X); //y1=t0^p^2 + FP12_YYY_mul(&y1,&y0); // y1=y0*y1 + FP12_YYY_conj(&t0,&t0); // t0=~t0 + FP12_YYY_copy(&y3,&t0); + FP12_YYY_frob(&y3,&X); //y3=t0^p + FP12_YYY_mul(&y3,&t0); // y3=t0*y3 + FP12_YYY_usqr(&t0,&t0); // t0=t0^2 + FP12_YYY_mul(&y1,&t0); // y1=t0*y1 + + FP12_YYY_pow(&t0,&y3,x); // t0=y3^-u +#if SIGN_OF_X_ZZZ==POSITIVEX + FP12_YYY_conj(&t0,&t0); +#endif + FP12_YYY_usqr(&t0,&t0); //t0=t0^2 + FP12_YYY_conj(&t0,&t0); //t0=~t0 + FP12_YYY_mul(&y3,&t0); // y3=t0*y3 + + FP12_YYY_frob(r,&X); + FP12_YYY_copy(&y0,r); + FP12_YYY_frob(r,&X); + FP12_YYY_mul(&y0,r); + FP12_YYY_frob(r,&X); + FP12_YYY_mul(&y0,r); + + FP12_YYY_usqr(r,&y3); //r=y3^2 + FP12_YYY_mul(r,&y2); //r=y2*r + FP12_YYY_copy(&y3,r); + FP12_YYY_mul(&y3,&y0); // y3=r*y0 + FP12_YYY_mul(r,&y1); // r=r*y1 + FP12_YYY_usqr(r,r); // r=r^2 + FP12_YYY_mul(r,&y3); // r=r*y3 + FP12_YYY_reduce(r); +#else + // Ghamman & Fouotsa Method + FP12_YYY_usqr(&y0,r); + FP12_YYY_pow(&y1,&y0,x); +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(&y1,&y1); +#endif + + + BIG_XXX_fshr(x,1); + FP12_YYY_pow(&y2,&y1,x); +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(&y2,&y2); +#endif + + + BIG_XXX_fshl(x,1); // x must be even + FP12_YYY_conj(&y3,r); + FP12_YYY_mul(&y1,&y3); + + FP12_YYY_conj(&y1,&y1); + FP12_YYY_mul(&y1,&y2); + + FP12_YYY_pow(&y2,&y1,x); +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(&y2,&y2); +#endif + + FP12_YYY_pow(&y3,&y2,x); +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(&y3,&y3); +#endif + FP12_YYY_conj(&y1,&y1); + FP12_YYY_mul(&y3,&y1); + + FP12_YYY_conj(&y1,&y1); + FP12_YYY_frob(&y1,&X); + FP12_YYY_frob(&y1,&X); + FP12_YYY_frob(&y1,&X); + FP12_YYY_frob(&y2,&X); + FP12_YYY_frob(&y2,&X); + FP12_YYY_mul(&y1,&y2); + + FP12_YYY_pow(&y2,&y3,x); +#if SIGN_OF_X_ZZZ==NEGATIVEX + FP12_YYY_conj(&y2,&y2); +#endif + FP12_YYY_mul(&y2,&y0); + FP12_YYY_mul(&y2,r); + + FP12_YYY_mul(&y1,&y2); + FP12_YYY_copy(&y2,&y3); + FP12_YYY_frob(&y2,&X); + FP12_YYY_mul(&y1,&y2); + FP12_YYY_copy(r,&y1); + FP12_YYY_reduce(r); +#endif +} + +#ifdef USE_GLV_ZZZ +/* GLV method */ +static void glv(BIG_XXX u[2],BIG_XXX e) +{ +#if PAIRING_FRIENDLY_ZZZ==BN + int i,j; + BIG_XXX v[2],t,q; + DBIG_XXX d; + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + for (i=0; i<2; i++) + { + BIG_XXX_rcopy(t,CURVE_W_ZZZ[i]); + BIG_XXX_mul(d,t,e); + BIG_XXX_ddiv(v[i],d,q); + BIG_XXX_zero(u[i]); + } + BIG_XXX_copy(u[0],e); + for (i=0; i<2; i++) + for (j=0; j<2; j++) + { + BIG_XXX_rcopy(t,CURVE_SB_ZZZ[j][i]); + BIG_XXX_modmul(t,v[j],t,q); + BIG_XXX_add(u[i],u[i],q); + BIG_XXX_sub(u[i],u[i],t); + BIG_XXX_mod(u[i],q); + } + +#else +// -(x^2).P = (Beta.x,y) + + BIG_XXX x,x2,q; + BIG_XXX_rcopy(x,CURVE_Bnx_ZZZ); + BIG_XXX_smul(x2,x,x); + BIG_XXX_copy(u[0],e); + BIG_XXX_mod(u[0],x2); + BIG_XXX_copy(u[1],e); + BIG_XXX_sdiv(u[1],x2); + + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_sub(u[1],q,u[1]); + +#endif + + return; +} +#endif // USE_GLV + +/* Galbraith & Scott Method */ +static void gs(BIG_XXX u[4],BIG_XXX e) +{ + int i; +#if PAIRING_FRIENDLY_ZZZ==BN + int j; + BIG_XXX v[4],t,q; + DBIG_XXX d; + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + for (i=0; i<4; i++) + { + BIG_XXX_rcopy(t,CURVE_WB_ZZZ[i]); + BIG_XXX_mul(d,t,e); + BIG_XXX_ddiv(v[i],d,q); + BIG_XXX_zero(u[i]); + } + + BIG_XXX_copy(u[0],e); + for (i=0; i<4; i++) + for (j=0; j<4; j++) + { + BIG_XXX_rcopy(t,CURVE_BB_ZZZ[j][i]); + BIG_XXX_modmul(t,v[j],t,q); + BIG_XXX_add(u[i],u[i],q); + BIG_XXX_sub(u[i],u[i],t); + BIG_XXX_mod(u[i],q); + } + +#else + + BIG_XXX x,w,q; + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + BIG_XXX_rcopy(x,CURVE_Bnx_ZZZ); + BIG_XXX_copy(w,e); + + for (i=0; i<3; i++) + { + BIG_XXX_copy(u[i],w); + BIG_XXX_mod(u[i],x); + BIG_XXX_sdiv(w,x); + } + BIG_XXX_copy(u[3],w); + +#if SIGN_OF_X_ZZZ==NEGATIVEX + BIG_XXX_modneg(u[1],u[1],q); + BIG_XXX_modneg(u[3],u[3],q); +#endif + +#endif + + + + return; +} + +/* Multiply P by e in group G1 */ +void PAIR_ZZZ_G1mul(ECP_ZZZ *P,BIG_XXX e) +{ +#ifdef USE_GLV_ZZZ /* Note this method is patented */ + int np,nn; + ECP_ZZZ Q; + FP_YYY cru; + BIG_XXX t,q; + BIG_XXX u[2]; + + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + glv(u,e); + + ECP_ZZZ_affine(P); + ECP_ZZZ_copy(&Q,P); + FP_YYY_rcopy(&cru,CURVE_Cru_ZZZ); + FP_YYY_mul(&(Q.x),&(Q.x),&cru); + + /* note that -a.B = a.(-B). Use a or -a depending on which is smaller */ + + np=BIG_XXX_nbits(u[0]); + BIG_XXX_modneg(t,u[0],q); + nn=BIG_XXX_nbits(t); + if (nn<np) + { + BIG_XXX_copy(u[0],t); + ECP_ZZZ_neg(P); + } + + np=BIG_XXX_nbits(u[1]); + BIG_XXX_modneg(t,u[1],q); + nn=BIG_XXX_nbits(t); + if (nn<np) + { + BIG_XXX_copy(u[1],t); + ECP_ZZZ_neg(&Q); + } + BIG_XXX_norm(u[0]); + BIG_XXX_norm(u[1]); + ECP_ZZZ_mul2(P,&Q,u[0],u[1]); + +#else + ECP_ZZZ_mul(P,e); +#endif +} + +/* Multiply P by e in group G2 */ +void PAIR_ZZZ_G2mul(ECP2_ZZZ *P,BIG_XXX e) +{ +#ifdef USE_GS_G2_ZZZ /* Well I didn't patent it :) */ + int i,np,nn; + ECP2_ZZZ Q[4]; + FP2_YYY X; + FP_YYY fx,fy; + BIG_XXX x,y,u[4]; + + FP_YYY_rcopy(&fx,Fra_YYY); + FP_YYY_rcopy(&fy,Frb_YYY); + FP2_YYY_from_FPs(&X,&fx,&fy); + +#if SEXTIC_TWIST_ZZZ==M_TYPE + FP2_YYY_inv(&X,&X); + FP2_YYY_norm(&X); +#endif + + BIG_XXX_rcopy(y,CURVE_Order_ZZZ); + gs(u,e); + + + ECP2_ZZZ_affine(P); + ECP2_ZZZ_copy(&Q[0],P); + for (i=1; i<4; i++) + { + ECP2_ZZZ_copy(&Q[i],&Q[i-1]); + ECP2_ZZZ_frob(&Q[i],&X); + } + for (i=0; i<4; i++) + { + np=BIG_XXX_nbits(u[i]); + BIG_XXX_modneg(x,u[i],y); + nn=BIG_XXX_nbits(x); + if (nn<np) + { + BIG_XXX_copy(u[i],x); + ECP2_ZZZ_neg(&Q[i]); + } + BIG_XXX_norm(u[i]); + } + + ECP2_ZZZ_mul4(P,Q,u); + +#else + ECP2_ZZZ_mul(P,e); +#endif +} + +/* f=f^e */ +void PAIR_ZZZ_GTpow(FP12_YYY *f,BIG_XXX e) +{ +#ifdef USE_GS_GT_ZZZ /* Note that this option requires a lot of RAM! Maybe better to use compressed XTR method, see fp4.c */ + int i,np,nn; + FP12_YYY g[4]; + FP2_YYY X; + BIG_XXX t,q; + FP_YYY fx,fy; + BIG_XXX u[4]; + + FP_YYY_rcopy(&fx,Fra_YYY); + FP_YYY_rcopy(&fy,Frb_YYY); + FP2_YYY_from_FPs(&X,&fx,&fy); + + BIG_XXX_rcopy(q,CURVE_Order_ZZZ); + gs(u,e); + + FP12_YYY_copy(&g[0],f); + for (i=1; i<4; i++) + { + FP12_YYY_copy(&g[i],&g[i-1]); + FP12_YYY_frob(&g[i],&X); + } + + for (i=0; i<4; i++) + { + np=BIG_XXX_nbits(u[i]); + BIG_XXX_modneg(t,u[i],q); + nn=BIG_XXX_nbits(t); + if (nn<np) + { + BIG_XXX_copy(u[i],t); + FP12_YYY_conj(&g[i],&g[i]); + } + BIG_XXX_norm(u[i]); + } + FP12_YYY_pow4(f,g,u); + +#else + FP12_YYY_pow(f,f,e); +#endif +} + +#ifdef HAS_MAIN + +int main() +{ + int i; + char byt[32]; + csprng rng; + BIG_XXX xa,xb,ya,yb,w,a,b,t1,q,u[2],v[4],m,r; + ECP2_ZZZ P,G; + ECP_ZZZ Q,R; + FP12_YYY g,gp; + FP4_YYY t,c,cp,cpm1,cpm2; + FP2_YYY x,y,X; + + BIG_XXX_rcopy(a,CURVE_Fra); + BIG_XXX_rcopy(b,CURVE_Frb); + FP2_YYY_from_BIGs(&X,a,b); + + BIG_XXX_rcopy(xa,CURVE_Gx); + BIG_XXX_rcopy(ya,CURVE_Gy); + + ECP_ZZZ_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_ZZZ_output(&Q); + printf("\n"); + + BIG_XXX_rcopy(xa,CURVE_Pxa); + BIG_XXX_rcopy(xb,CURVE_Pxb); + BIG_XXX_rcopy(ya,CURVE_Pya); + BIG_XXX_rcopy(yb,CURVE_Pyb); + + FP2_YYY_from_BIGs(&x,xa,xb); + FP2_YYY_from_BIGs(&y,ya,yb); + + ECP2_ZZZ_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_ZZZ_output(&P); + printf("\n"); + + for (i=0; i<1000; i++ ) + { + PAIR_ZZZ_ate(&g,&P,&Q); + PAIR_ZZZ_fexp(&g); + } + printf("g= "); + FP12_YYY_output(&g); + printf("\n"); + +} + +#endif
