/* Functions to support M-Pin Full */ public static int PRECOMPUTE(sbyte[] TOKEN, sbyte[] CID, sbyte[] G1, sbyte[] G2) { ECP P, T; FP12 g; T = ECP.fromBytes(TOKEN); if (T.is_infinity()) { return(INVALID_POINT); } P = mapit(CID); ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa), new BIG(ROM.CURVE_Pxb)), new FP2(new BIG(ROM.CURVE_Pya), new BIG(ROM.CURVE_Pyb))); g = PAIR.ate(Q, T); g = PAIR.fexp(g); g.toBytes(G1); g = PAIR.ate(Q, P); g = PAIR.fexp(g); g.toBytes(G2); return(0); }
/* copy this=P */ public void copy(ECP2 P) { x.copy(P.x); y.copy(P.y); z.copy(P.z); INF = P.INF; }
/* set this-=Q */ public int sub(ECP2 Q) { Q.neg(); int D = add(Q); Q.neg(); return(D); }
/* Extract Server Secret SST=S*Q where Q is fixed generator in G2 and S is master secret */ public static int GET_SERVER_SECRET(sbyte[] S, sbyte[] SST) { ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa), new BIG(ROM.CURVE_Pxb)), new FP2(new BIG(ROM.CURVE_Pya), new BIG(ROM.CURVE_Pyb))); BIG s = BIG.fromBytes(S); Q = PAIR.G2mul(Q, s); Q.toBytes(SST); return(0); }
/** * Verify a WBB signature for a certain message * * @param pk Public key * @param sig Signature * @param m Message * @return True iff valid */ public static bool weakBBVerify(ECP2 pk, ECP sig, BIG m) { ECP2 p = new ECP2(); p.Copy(pk); p.Add(IdemixUtils.GenG2.Mul(m)); p.Affine(); return(PAIR.FExp(PAIR.Ate(p, sig)).Equals(IdemixUtils.GenGT)); }
/* Optimal R-ate pairing */ public static FP12 ate(ECP2 P, ECP Q) { FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); BIG x = new BIG(ROM.CURVE_Bnx); BIG n = new BIG(x); ECP2 K = new ECP2(); FP12 lv; n.pmul(6); n.dec(2); n.norm(); P.affine(); Q.affine(); FP Qx = new FP(Q.getx()); FP Qy = new FP(Q.gety()); ECP2 A = new ECP2(); FP12 r = new FP12(1); A.copy(P); int nb = n.nbits(); for (int i = nb - 2; i >= 1; i--) { lv = line(A, A, Qx, Qy); r.smul(lv); if (n.bit(i) == 1) { lv = line(A, P, Qx, Qy); r.smul(lv); } r.sqr(); } lv = line(A, A, Qx, Qy); r.smul(lv); /* R-ate fixup */ r.conj(); K.copy(P); K.frob(f); A.neg(); lv = line(A, K, Qx, Qy); r.smul(lv); K.frob(f); K.neg(); lv = line(A, K, Qx, Qy); r.smul(lv); return(r); }
/* Multiply P by e in group G2 */ public static ECP2 G2Mul(ECP2 P, BIG e) { ECP2 R; if (USE_GS_G2) { ECP2[] Q = new ECP2[4]; FP2 f = new FP2(new BIG(ROM.Fra), new BIG(ROM.Frb)); if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { f.Inverse(); f.Norm(); } BIG q = new BIG(ROM.CURVE_Order); BIG[] u = GS(e); BIG t = new BIG(0); int i, np, nn; //P.affine(); Q[0] = new ECP2(); Q[0].Copy(P); for (i = 1; i < 4; i++) { Q[i] = new ECP2(); Q[i].Copy(Q[i - 1]); Q[i].Frob(f); } for (i = 0; i < 4; i++) { np = u[i].NBits(); t.Copy(BIG.ModNeg(u[i], q)); nn = t.NBits(); if (nn < np) { u[i].Copy(t); Q[i].Neg(); } u[i].Norm(); //Q[i].affine(); } R = ECP2.Mul4(Q, u); } else { R = P.Mul(e); } return(R); }
/* needed for SOK */ public static ECP2 mapit2(sbyte[] h) { BIG q = new BIG(ROM.Modulus); BIG x = BIG.fromBytes(h); BIG one = new BIG(1); FP2 X; ECP2 Q, T, K; x.mod(q); while (true) { X = new FP2(one, x); Q = new ECP2(X); if (!Q.is_infinity()) { break; } x.inc(1); x.norm(); } /* Fast Hashing to G2 - Fuentes-Castaneda, Knapp and Rodriguez-Henriquez */ BIG Fra = new BIG(ROM.CURVE_Fra); BIG Frb = new BIG(ROM.CURVE_Frb); X = new FP2(Fra, Frb); x = new BIG(ROM.CURVE_Bnx); T = new ECP2(); T.copy(Q); T.mul(x); T.neg(); K = new ECP2(); K.copy(T); K.dbl(); K.add(T); K.affine(); K.frob(X); Q.frob(X); Q.frob(X); Q.frob(X); Q.add(T); Q.add(K); T.frob(X); T.frob(X); Q.add(T); Q.affine(); return(Q); }
/* W=W1+W2 in group G2 */ public static int RECOMBINE_G2(sbyte[] W1, sbyte[] W2, sbyte[] W) { ECP2 P = ECP2.fromBytes(W1); ECP2 Q = ECP2.fromBytes(W2); if (P.is_infinity() || Q.is_infinity()) { return(INVALID_POINT); } P.add(Q); P.toBytes(W); return(0); }
/** * Converts an amcl.BN256.ECP2 into an ECP2 protobuf object. * * @param w an ECP2 to be transformed into a protobuf object * @return a protobuf representation of the ECP2 */ public static Protos.Idemix.ECP2 ToProto(this ECP2 w) { byte[] valueXA = new byte[FIELD_BYTES]; byte[] valueXB = new byte[FIELD_BYTES]; byte[] valueYA = new byte[FIELD_BYTES]; byte[] valueYB = new byte[FIELD_BYTES]; w.X.A.ToBytes(valueXA); w.X.B.ToBytes(valueXB); w.Y.A.ToBytes(valueYA); w.Y.B.ToBytes(valueYB); Protos.Idemix.ECP2 ecp2 = new Protos.Idemix.ECP2(); ecp2.Xa = ByteString.CopyFrom(valueXA); ecp2.Xb = ByteString.CopyFrom(valueXB); ecp2.Ya = ByteString.CopyFrom(valueYA); ecp2.Yb = ByteString.CopyFrom(valueYB); return(ecp2); }
/* Conditional move of Q to P dependant on d */ public void cmove(ECP2 Q, int d) { x.cmove(Q.x, d); y.cmove(Q.y, d); z.cmove(Q.z, d); bool bd; if (d == 0) { bd = false; } else { bd = true; } INF ^= (INF ^ Q.INF) & bd; }
/* Multiply P by e in group G2 */ public static ECP2 G2mul(ECP2 P, BIG e) { ECP2 R; if (ROM.USE_GS_G2) { ECP2[] Q = new ECP2[4]; FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); BIG q = new BIG(ROM.CURVE_Order); BIG[] u = gs(e); BIG t = new BIG(0); int i, np, nn; P.affine(); Q[0] = new ECP2(); Q[0].copy(P); for (i = 1; i < 4; i++) { Q[i] = new ECP2(); Q[i].copy(Q[i - 1]); Q[i].frob(f); } for (i = 0; i < 4; i++) { np = u[i].nbits(); t.copy(BIG.modneg(u[i], q)); nn = t.nbits(); if (nn < np) { u[i].copy(t); Q[i].neg(); } } R = ECP2.mul4(Q, u); } else { R = P.mul(e); } return(R); }
/* Constant time select from pre-computed table */ public void select(ECP2[] W, int b) { ECP2 MP = new ECP2(); int m = b >> 31; int babs = (b ^ m) - m; babs = (babs - 1) / 2; cmove(W[0], teq(babs, 0)); // conditional move cmove(W[1], teq(babs, 1)); cmove(W[2], teq(babs, 2)); cmove(W[3], teq(babs, 3)); cmove(W[4], teq(babs, 4)); cmove(W[5], teq(babs, 5)); cmove(W[6], teq(babs, 6)); cmove(W[7], teq(babs, 7)); MP.copy(this); MP.neg(); cmove(MP, (int)(m & 1)); }
/* Test if P == Q */ public bool Equals(ECP2 Q) { if (is_infinity() && Q.is_infinity()) { return(true); } if (is_infinity() || Q.is_infinity()) { return(false); } FP2 zs2 = new FP2(z); zs2.sqr(); FP2 zo2 = new FP2(Q.z); zo2.sqr(); FP2 zs3 = new FP2(zs2); zs3.mul(z); FP2 zo3 = new FP2(zo2); zo3.mul(Q.z); zs2.mul(Q.x); zo2.mul(x); if (!zs2.Equals(zo2)) { return(false); } zs3.mul(Q.y); zo3.mul(y); if (!zs3.Equals(zo3)) { return(false); } return(true); }
/* P=u0.Q0+u1*Q1+u2*Q2+u3*Q3 */ public static ECP2 mul4(ECP2[] Q, BIG[] u) { int i, j, nb; int[] a = new int[4]; ECP2 T = new ECP2(); ECP2 C = new ECP2(); ECP2 P = new ECP2(); ECP2[] W = new ECP2[8]; BIG mt = new BIG(); BIG[] t = new BIG[4]; sbyte[] w = new sbyte[ROM.NLEN * ROM.BASEBITS + 1]; for (i = 0; i < 4; i++) { t[i] = new BIG(u[i]); Q[i].affine(); } /* precompute table */ W[0] = new ECP2(); W[0].copy(Q[0]); W[0].sub(Q[1]); W[1] = new ECP2(); W[1].copy(W[0]); W[2] = new ECP2(); W[2].copy(W[0]); W[3] = new ECP2(); W[3].copy(W[0]); W[4] = new ECP2(); W[4].copy(Q[0]); W[4].add(Q[1]); W[5] = new ECP2(); W[5].copy(W[4]); W[6] = new ECP2(); W[6].copy(W[4]); W[7] = new ECP2(); W[7].copy(W[4]); T.copy(Q[2]); T.sub(Q[3]); W[1].sub(T); W[2].add(T); W[5].sub(T); W[6].add(T); T.copy(Q[2]); T.add(Q[3]); W[0].sub(T); W[3].add(T); W[4].sub(T); W[7].add(T); multiaffine(8, W); /* if multiplier is even add 1 to multiplier, and add P to correction */ mt.zero(); C.inf(); for (i = 0; i < 4; i++) { if (t[i].parity() == 0) { t[i].inc(1); t[i].norm(); C.add(Q[i]); } mt.add(t[i]); mt.norm(); } nb = 1 + mt.nbits(); /* convert exponent to signed 1-bit window */ for (j = 0; j < nb; j++) { for (i = 0; i < 4; i++) { a[i] = (sbyte)(t[i].lastbits(2) - 2); t[i].dec(a[i]); t[i].norm(); t[i].fshr(1); } w[j] = (sbyte)(8 * a[0] + 4 * a[1] + 2 * a[2] + a[3]); } w[nb] = (sbyte)(8 * t[0].lastbits(2) + 4 * t[1].lastbits(2) + 2 * t[2].lastbits(2) + t[3].lastbits(2)); P.copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { T.select(W, w[i]); P.dbl(); P.add(T); } P.sub(C); // apply correction P.affine(); return(P); }
/* P*=e */ public ECP2 mul(BIG e) { /* fixed size windows */ int i, b, nb, m, s, ns; BIG mt = new BIG(); BIG t = new BIG(); ECP2 P = new ECP2(); ECP2 Q = new ECP2(); ECP2 C = new ECP2(); ECP2[] W = new ECP2[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 3) / 4]; if (is_infinity()) { return(new ECP2()); } affine(); /* precompute table */ Q.copy(this); Q.dbl(); W[0] = new ECP2(); W[0].copy(this); for (i = 1; i < 8; i++) { W[i] = new ECP2(); W[i].copy(W[i - 1]); W[i].add(Q); } /* convert the table to affine */ multiaffine(8, W); /* make exponent odd - add 2P if even, P if odd */ t.copy(e); s = t.parity(); t.inc(1); t.norm(); ns = t.parity(); mt.copy(t); mt.inc(1); mt.norm(); t.cmove(mt, s); Q.cmove(this, ns); C.copy(Q); nb = 1 + (t.nbits() + 3) / 4; /* convert exponent to signed 4-bit window */ for (i = 0; i < nb; i++) { w[i] = (sbyte)(t.lastbits(5) - 16); t.dec(w[i]); t.norm(); t.fshr(4); } w[nb] = (sbyte)t.lastbits(5); P.copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { Q.select(W, w[i]); P.dbl(); P.dbl(); P.dbl(); P.dbl(); P.add(Q); } P.sub(C); P.affine(); return(P); }
/* Implement step 2 of MPin protocol on server side */ public static int SERVER_2(int date, sbyte[] HID, sbyte[] HTID, sbyte[] Y, sbyte[] SST, sbyte[] xID, sbyte[] xCID, sbyte[] mSEC, sbyte[] E, sbyte[] F) { BIG q = new BIG(ROM.Modulus); ECP2 Q = new ECP2(new FP2(new BIG(ROM.CURVE_Pxa), new BIG(ROM.CURVE_Pxb)), new FP2(new BIG(ROM.CURVE_Pya), new BIG(ROM.CURVE_Pyb))); ECP2 sQ = ECP2.fromBytes(SST); if (sQ.is_infinity()) { return(INVALID_POINT); } ECP R; if (date != 0) { R = ECP.fromBytes(xCID); } else { if (xID == null) { return(BAD_PARAMS); } R = ECP.fromBytes(xID); } if (R.is_infinity()) { return(INVALID_POINT); } BIG y = BIG.fromBytes(Y); ECP P; if (date != 0) { P = ECP.fromBytes(HTID); } else { if (HID == null) { return(BAD_PARAMS); } P = ECP.fromBytes(HID); } if (P.is_infinity()) { return(INVALID_POINT); } P = PAIR.G1mul(P, y); P.add(R); R = ECP.fromBytes(mSEC); if (R.is_infinity()) { return(INVALID_POINT); } FP12 g; // FP12 g1=new FP12(0); g = PAIR.ate2(Q, R, sQ, P); g = PAIR.fexp(g); if (!g.isunity()) { if (HID != null && xID != null && E != null && F != null) { g.toBytes(E); if (date != 0) { P = ECP.fromBytes(HID); if (P.is_infinity()) { return(INVALID_POINT); } R = ECP.fromBytes(xID); if (R.is_infinity()) { return(INVALID_POINT); } P = PAIR.G1mul(P, y); P.add(R); } g = PAIR.ate(Q, P); g = PAIR.fexp(g); g.toBytes(F); } return(BAD_PIN); } return(0); }
/* calculate common key on server side */ /* Z=r.A - no time permits involved */ public static int SERVER_KEY(sbyte[] Z, sbyte[] SST, sbyte[] W, sbyte[] xID, sbyte[] xCID, sbyte[] SK) { HASH H = new HASH(); sbyte[] t = new sbyte[EFS]; ECP2 sQ = ECP2.fromBytes(SST); if (sQ.is_infinity()) { return(INVALID_POINT); } ECP R = ECP.fromBytes(Z); if (R.is_infinity()) { return(INVALID_POINT); } ECP U; if (xCID != null) { U = ECP.fromBytes(xCID); } else { U = ECP.fromBytes(xID); } if (U.is_infinity()) { return(INVALID_POINT); } BIG w = BIG.fromBytes(W); U = PAIR.G1mul(U, w); FP12 g = PAIR.ate(sQ, R); g = PAIR.fexp(g); FP4 c = g.trace(); c.geta().A.toBytes(t); H.process_array(t); c.geta().B.toBytes(t); H.process_array(t); c.getb().A.toBytes(t); H.process_array(t); c.getb().B.toBytes(t); H.process_array(t); U.X.toBytes(t); H.process_array(t); U.Y.toBytes(t); H.process_array(t); t = H.hash(); for (int i = 0; i < PAS; i++) { SK[i] = t[i]; } return(0); }
/* this+=Q - return 0 for add, 1 for double, -1 for O */ public int add(ECP2 Q) { if (INF) { copy(Q); return(-1); } if (Q.INF) { return(-1); } bool aff = false; if (Q.z.isunity()) { aff = true; } FP2 A, C; FP2 B = new FP2(z); FP2 D = new FP2(z); if (!aff) { A = new FP2(Q.z); C = new FP2(Q.z); A.sqr(); B.sqr(); C.mul(A); D.mul(B); A.mul(x); C.mul(y); } else { A = new FP2(x); C = new FP2(y); B.sqr(); D.mul(B); } B.mul(Q.x); B.sub(A); D.mul(Q.y); D.sub(C); if (B.iszilch()) { if (D.iszilch()) { dbl(); return(1); } else { INF = true; return(-1); } } if (!aff) { z.mul(Q.z); } z.mul(B); FP2 e = new FP2(B); e.sqr(); B.mul(e); A.mul(e); e.copy(A); e.add(A); e.add(B); x.copy(D); x.sqr(); x.sub(e); A.sub(x); y.copy(A); y.mul(D); C.mul(B); y.sub(C); x.norm(); y.norm(); z.norm(); return(0); }
/** * ecpToBytes turns an ECP2 into a byte array * * @param e the ECP2 to turn into bytes * @return a byte array representation of the ECP2 */ public static byte[] ToBytes(this ECP2 e) { byte[] ret = new byte[4 * FIELD_BYTES]; e.ToBytes(ret); return(ret); }
/* Line function */ public static FP12 Line(ECP2 A, ECP2 B, FP Qx, FP Qy) { //System.out.println("Into line"); FP4 a, b, c; // Edits here // c=new FP4(0); if (A == B) { // Doubling FP2 XX = new FP2(A.GetX()); //X FP2 YY = new FP2(A.GetY()); //Y FP2 ZZ = new FP2(A.GetZ()); //Z FP2 YZ = new FP2(YY); //Y YZ.Mul(ZZ); //YZ XX.Sqr(); //X^2 YY.Sqr(); //Y^2 ZZ.Sqr(); //Z^2 YZ.IMul(4); YZ.Neg(); YZ.Norm(); //-2YZ YZ.PMul(Qy); //-2YZ.Ys XX.IMul(6); //3X^2 XX.PMul(Qx); //3X^2.Xs int sb = 3 * ROM.CURVE_B_I; ZZ.IMul(sb); if (ECP.SEXTIC_TWIST == ECP.D_TYPE) { ZZ.Div_Ip2(); } if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { ZZ.Mul_Ip(); ZZ.Add(ZZ); YZ.Mul_Ip(); YZ.Norm(); } ZZ.Norm(); // 3b.Z^2 YY.Add(YY); ZZ.Sub(YY); ZZ.Norm(); // 3b.Z^2-Y^2 a = new FP4(YZ, ZZ); // -2YZ.Ys | 3b.Z^2-Y^2 | 3X^2.Xs if (ECP.SEXTIC_TWIST == ECP.D_TYPE) { b = new FP4(XX); // L(0,1) | L(0,0) | L(1,0) c = new FP4(0); } if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { b = new FP4(0); c = new FP4(XX); c.Times_I(); } A.Dbl(); } else { // Addition - assume B is affine FP2 X1 = new FP2(A.GetX()); // X1 FP2 Y1 = new FP2(A.GetY()); // Y1 FP2 T1 = new FP2(A.GetZ()); // Z1 FP2 T2 = new FP2(A.GetZ()); // Z1 T1.Mul(B.GetY()); // T1=Z1.Y2 T2.Mul(B.GetX()); // T2=Z1.X2 X1.Sub(T2); X1.Norm(); // X1=X1-Z1.X2 Y1.Sub(T1); Y1.Norm(); // Y1=Y1-Z1.Y2 T1.Copy(X1); // T1=X1-Z1.X2 X1.PMul(Qy); // X1=(X1-Z1.X2).Ys if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { X1.Mul_Ip(); X1.Norm(); } T1.Mul(B.GetY()); // T1=(X1-Z1.X2).Y2 T2.Copy(Y1); // T2=Y1-Z1.Y2 T2.Mul(B.GetX()); // T2=(Y1-Z1.Y2).X2 T2.Sub(T1); T2.Norm(); // T2=(Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 Y1.PMul(Qx); Y1.Neg(); Y1.Norm(); // Y1=-(Y1-Z1.Y2).Xs a = new FP4(X1, T2); // (X1-Z1.X2).Ys | (Y1-Z1.Y2).X2 - (X1-Z1.X2).Y2 | - (Y1-Z1.Y2).Xs if (ECP.SEXTIC_TWIST == ECP.D_TYPE) { b = new FP4(Y1); c = new FP4(0); } if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { b = new FP4(0); c = new FP4(Y1); c.Times_I(); } A.Add(B); } //System.out.println("Out of line"); return(new FP12(a, b, c)); }
/* Optimal R-ate double pairing e(P,Q).e(R,S) */ public static FP12 Ate2(ECP2 P1, ECP Q1, ECP2 R1, ECP S1) { FP2 f; BIG x = new BIG(ROM.CURVE_Bnx); BIG n = new BIG(x); ECP2 K = new ECP2(); FP12 lv; int bt; ECP2 P = new ECP2(P1); ECP Q = new ECP(Q1); P.Affine(); Q.Affine(); ECP2 R = new ECP2(R1); ECP S = new ECP(S1); R.Affine(); S.Affine(); if (ECP.CURVE_PAIRING_TYPE == ECP.BN) { f = new FP2(new BIG(ROM.Fra), new BIG(ROM.Frb)); if (ECP.SEXTIC_TWIST == ECP.M_TYPE) { f.Inverse(); f.Norm(); } n.PMul(6); if (ECP.SIGN_OF_X == ECP.POSITIVEX) { n.Inc(2); } else { n.Dec(2); } } else { n.Copy(x); } n.Norm(); BIG n3 = new BIG(n); n3.PMul(3); n3.Norm(); FP Qx = new FP(Q.GetX()); FP Qy = new FP(Q.GetY()); FP Sx = new FP(S.GetX()); FP Sy = new FP(S.GetY()); ECP2 A = new ECP2(); ECP2 B = new ECP2(); FP12 r = new FP12(1); A.Copy(P); B.Copy(R); ECP2 MP = new ECP2(); MP.Copy(P); MP.Neg(); ECP2 MR = new ECP2(); MR.Copy(R); MR.Neg(); int nb = n3.NBits(); for (int i = nb - 2; i >= 1; i--) { r.Sqr(); lv = Line(A, A, Qx, Qy); r.SMul(lv, ECP.SEXTIC_TWIST); lv = Line(B, B, Sx, Sy); r.SMul(lv, ECP.SEXTIC_TWIST); bt = n3.Bit(i) - n.Bit(i); // bt=n.bit(i); if (bt == 1) { lv = Line(A, P, Qx, Qy); r.SMul(lv, ECP.SEXTIC_TWIST); lv = Line(B, R, Sx, Sy); r.SMul(lv, ECP.SEXTIC_TWIST); } if (bt == -1) { //P.neg(); lv = Line(A, MP, Qx, Qy); r.SMul(lv, ECP.SEXTIC_TWIST); //P.neg(); //R.neg(); lv = Line(B, MR, Sx, Sy); r.SMul(lv, ECP.SEXTIC_TWIST); //R.neg(); } } if (ECP.SIGN_OF_X == ECP.NEGATIVEX) { r.Conj(); } /* R-ate fixup required for BN curves */ if (ECP.CURVE_PAIRING_TYPE == ECP.BN) { if (ECP.SIGN_OF_X == ECP.NEGATIVEX) { // r.conj(); A.Neg(); B.Neg(); } K.Copy(P); K.Frob(f); lv = Line(A, K, Qx, Qy); r.SMul(lv, ECP.SEXTIC_TWIST); K.Frob(f); K.Neg(); lv = Line(A, K, Qx, Qy); r.SMul(lv, ECP.SEXTIC_TWIST); K.Copy(R); K.Frob(f); lv = Line(B, K, Sx, Sy); r.SMul(lv, ECP.SEXTIC_TWIST); K.Frob(f); K.Neg(); lv = Line(B, K, Sx, Sy); r.SMul(lv, ECP.SEXTIC_TWIST); } return(r); }
/* Line function */ public static FP12 line(ECP2 A, ECP2 B, FP Qx, FP Qy) { ECP2 P = new ECP2(); FP4 a, b, c; P.copy(A); FP2 ZZ = new FP2(P.getz()); ZZ.sqr(); int D; if (A == B) { D = A.dbl(); // Check this return value in amcl_ec2.c } else { D = A.add(B); } if (D < 0) { return(new FP12(1)); } FP2 Z3 = new FP2(A.getz()); c = new FP4(0); if (D == 0) { // Addition FP2 X = new FP2(B.getx()); FP2 Y = new FP2(B.gety()); FP2 T = new FP2(P.getz()); T.mul(Y); ZZ.mul(T); FP2 NY = new FP2(P.gety()); NY.neg(); ZZ.add(NY); Z3.pmul(Qy); T.mul(P.getx()); X.mul(NY); T.add(X); a = new FP4(Z3, T); ZZ.neg(); ZZ.pmul(Qx); b = new FP4(ZZ); } else { // Doubling FP2 X = new FP2(P.getx()); FP2 Y = new FP2(P.gety()); FP2 T = new FP2(P.getx()); T.sqr(); T.imul(3); Y.sqr(); Y.add(Y); Z3.mul(ZZ); Z3.pmul(Qy); X.mul(T); X.sub(Y); a = new FP4(Z3, X); T.neg(); ZZ.mul(T); ZZ.pmul(Qx); b = new FP4(ZZ); } return(new FP12(a, b, c)); }