/* return sqrt(this) mod Modulus */ public FP sqrt() { reduce(); BIG b = new BIG(p); if (ROM.MOD8 == 5) { b.dec(5); b.norm(); b.shr(3); FP i = new FP(this); i.x.shl(1); FP v = i.pow(b); i.mul(v); i.mul(v); i.x.dec(1); FP r = new FP(this); r.mul(v); r.mul(i); r.reduce(); return(r); } else { b.inc(1); b.norm(); b.shr(2); return(pow(b)); } }
/* this=this^e */ public FP12 pow(BIG e) { norm(); e.norm(); FP12 w = new FP12(this); BIG z = new BIG(e); FP12 r = new FP12(1); while (true) { int bt = z.parity(); z.fshr(1); if (bt == 1) { r.mul(w); } if (z.iszilch()) { break; } w.usqr(); } r.reduce(); return(r); }
/* return this^e mod Modulus */ public FP pow(BIG e) { int bt; FP r = new FP(1); e.norm(); x.norm(); FP m = new FP(this); while (true) { bt = e.parity(); e.fshr(1); if (bt == 1) { r.mul(m); } if (e.iszilch()) { break; } m.sqr(); } r.x.mod(p); return(r); }
/* return this^e mod m */ public virtual BIG powmod(BIG e, BIG m) { int bt; norm(); e.norm(); BIG a = new BIG(1); BIG z = new BIG(e); BIG s = new BIG(this); while (true) { bt = z.parity(); z.fshr(1); if (bt == 1) { a = modmul(a, s, m); } if (z.iszilch()) { break; } s = modsqr(s, m); } return(a); }
/* a=1/a mod 2^256. This is very fast! */ public virtual void invmod2m() { int i; BIG U = new BIG(0); BIG b = new BIG(0); BIG c = new BIG(0); U.inc(invmod256(lastbits(8))); for (i = 8; i < 256; i <<= 1) { b.copy(this); b.mod2m(i); BIG t1 = BIG.smul(U, b); t1.shr(i); c.copy(this); c.shr(i); c.mod2m(i); BIG t2 = BIG.smul(U, c); t2.mod2m(i); t1.add(t2); b = BIG.smul(t1, U); t1.copy(b); t1.mod2m(i); t2.one(); t2.shl(i); t1.rsub(t2); t1.norm(); t1.shl(i); U.add(t1); } this.copy(U); }
/* divide this by m */ public virtual void div(BIG m) { int k = 0; norm(); BIG e = new BIG(1); BIG b = new BIG(this); zero(); while (comp(b, m) >= 0) { e.fshl(1); m.fshl(1); k++; } while (k > 0) { m.fshr(1); e.fshr(1); if (comp(b, m) >= 0) { add(e); norm(); b.sub(m); b.norm(); } k--; } }
/* reduces this DBIG mod a DBIG in place */ /* public void mod(DBIG m) * { * int k=0; * if (comp(this,m)<0) return; * * do * { * m.shl(1); * k++; * } * while (comp(this,m)>=0); * * while (k>0) * { * m.shr(1); * if (comp(this,m)>=0) * { * sub(m); * norm(); * } * k--; * } * return; * * }*/ /* return this/c */ public virtual BIG div(BIG c) { int k = 0; DBIG m = new DBIG(c); BIG a = new BIG(0); BIG e = new BIG(1); norm(); while (comp(this, m) >= 0) { e.fshl(1); m.shl(1); k++; } while (k > 0) { m.shr(1); e.shr(1); if (comp(this, m) > 0) { a.add(e); a.norm(); sub(m); norm(); } k--; } return(a); }
/* r=x^n using XTR method on traces of FP12s */ public FP4 xtr_pow(BIG n) { FP4 a = new FP4(3); FP4 b = new FP4(this); FP4 c = new FP4(b); c.xtr_D(); FP4 t = new FP4(0); FP4 r = new FP4(0); n.norm(); int par = n.parity(); BIG v = new BIG(n); v.fshr(1); if (par == 0) { v.dec(1); v.norm(); } int nb = v.nbits(); for (int i = nb - 1; i >= 0; i--) { if (v.bit(i) != 1) { t.copy(b); conj(); c.conj(); b.xtr_A(a, this, c); conj(); c.copy(t); c.xtr_D(); a.xtr_D(); } else { t.copy(a); t.conj(); a.copy(b); a.xtr_D(); b.xtr_A(c, this, t); c.xtr_D(); } } if (par == 0) { r.copy(c); } else { r.copy(b); } r.reduce(); return(r); }
/* 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); }
/* 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); }
/* 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 */ public static ECP map(BIG u, int cb) { ECP P; BIG x = new BIG(u); BIG p = new BIG(ROM.Modulus); x.mod(p); while (true) { P = new ECP(x, cb); if (!P.is_infinity()) { break; } x.inc(1); x.norm(); } return(P); }
/* return a*b as DBIG */ public static DBIG mul(BIG a, BIG b) { DBIG c = new DBIG(0); long carry; a.norm(); b.norm(); for (int i = 0; i < ROM.NLEN; i++) { carry = 0; for (int j = 0; j < ROM.NLEN; j++) { carry = c.muladd(a.w[i], b.w[j], carry, i + j); } c.w[ROM.NLEN + i] = carry; } return(c); }
public static ECP mapit(sbyte[] h) { BIG q = new BIG(ROM.Modulus); BIG x = BIG.fromBytes(h); x.mod(q); ECP P; while (true) { P = new ECP(x, 0); if (!P.is_infinity()) { break; } x.inc(1); x.norm(); } return(P); }
/* returns u derived from P. Random value in range 1 to return value should then be added to u */ public static int unmap(BIG u, ECP P) { int s = P.S; ECP R; int r = 0; BIG x = P.X; u.copy(x); while (true) { u.dec(1); u.norm(); r++; R = new ECP(u, s); if (!R.is_infinity()) { break; } } return(r); }
/* return a^2 as DBIG */ public static DBIG sqr(BIG a) { DBIG c = new DBIG(0); long carry; a.norm(); for (int i = 0; i < ROM.NLEN; i++) { carry = 0; for (int j = i + 1; j < ROM.NLEN; j++) { carry = c.muladd(2 * a.w[i], a.w[j], carry, i + j); } c.w[ROM.NLEN + i] = carry; } for (int i = 0; i < ROM.NLEN; i++) { c.w[2 * i + 1] += c.muladd(a.w[i], a.w[i], 0, 2 * i); } c.norm(); return(c); }
/* 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); }
/* return e.this */ public ECP mul(BIG e) { if (e.iszilch() || is_infinity()) { return(new ECP()); } ECP P = new ECP(); if (ROM.CURVETYPE == ROM.MONTGOMERY) { /* use Ladder */ int nb, i, b; ECP D = new ECP(); ECP R0 = new ECP(); R0.copy(this); ECP R1 = new ECP(); R1.copy(this); R1.dbl(); D.copy(this); D.affine(); nb = e.nbits(); for (i = nb - 2; i >= 0; i--) { b = e.bit(i); P.copy(R1); P.dadd(R0, D); R0.cswap(R1, b); R1.copy(P); R0.dbl(); R0.cswap(R1, b); } P.copy(R0); } else { // fixed size windows int i, b, nb, m, s, ns; BIG mt = new BIG(); BIG t = new BIG(); ECP Q = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 3) / 4]; affine(); // precompute table Q.copy(this); Q.dbl(); W[0] = new ECP(); W[0].copy(this); for (i = 1; i < 8; i++) { W[i] = new ECP(); W[i].copy(W[i - 1]); W[i].add(Q); } // convert the table to affine if (ROM.CURVETYPE == ROM.WEIERSTRASS) { 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); // apply correction } P.affine(); return(P); }
/* Return e.this+f.Q */ public ECP mul2(BIG e, ECP Q, BIG f) { BIG te = new BIG(); BIG tf = new BIG(); BIG mt = new BIG(); ECP S = new ECP(); ECP T = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 1) / 2]; int i, s, ns, nb; sbyte a, b; affine(); Q.affine(); te.copy(e); tf.copy(f); // precompute table W[1] = new ECP(); W[1].copy(this); W[1].sub(Q); W[2] = new ECP(); W[2].copy(this); W[2].add(Q); S.copy(Q); S.dbl(); W[0] = new ECP(); W[0].copy(W[1]); W[0].sub(S); W[3] = new ECP(); W[3].copy(W[2]); W[3].add(S); T.copy(this); T.dbl(); W[5] = new ECP(); W[5].copy(W[1]); W[5].add(T); W[6] = new ECP(); W[6].copy(W[2]); W[6].add(T); W[4] = new ECP(); W[4].copy(W[5]); W[4].sub(S); W[7] = new ECP(); W[7].copy(W[6]); W[7].add(S); // convert the table to affine if (ROM.CURVETYPE == ROM.WEIERSTRASS) { multiaffine(8, W); } // if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction s = te.parity(); te.inc(1); te.norm(); ns = te.parity(); mt.copy(te); mt.inc(1); mt.norm(); te.cmove(mt, s); T.cmove(this, ns); C.copy(T); s = tf.parity(); tf.inc(1); tf.norm(); ns = tf.parity(); mt.copy(tf); mt.inc(1); mt.norm(); tf.cmove(mt, s); S.cmove(Q, ns); C.add(S); mt.copy(te); mt.add(tf); mt.norm(); nb = 1 + (mt.nbits() + 1) / 2; // convert exponent to signed 2-bit window for (i = 0; i < nb; i++) { a = (sbyte)(te.lastbits(3) - 4); te.dec(a); te.norm(); te.fshr(2); b = (sbyte)(tf.lastbits(3) - 4); tf.dec(b); tf.norm(); tf.fshr(2); w[i] = (sbyte)(4 * a + b); } w[nb] = (sbyte)(4 * te.lastbits(3) + tf.lastbits(3)); S.copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { T.select(W, w[i]); S.dbl(); S.dbl(); S.add(T); } S.sub(C); // apply correction S.affine(); return(S); }
/* reduce a DBIG to a BIG using the appropriate form of the modulus */ public static BIG mod(DBIG d) { BIG b; if (ROM.MODTYPE == ROM.PSEUDO_MERSENNE) { long v, tw; BIG t = d.Split(ROM.MODBITS); b = new BIG(d); unchecked { v = t.pmul((int)ROM.MConst); } tw = t.w[ROM.NLEN - 1]; t.w[ROM.NLEN - 1] &= ROM.TMASK; t.w[0] += (ROM.MConst * ((tw >> ROM.TBITS) + (v << (ROM.BASEBITS - ROM.TBITS)))); b.add(t); b.norm(); } if (ROM.MODTYPE == ROM.MONTGOMERY_FRIENDLY) { for (int i = 0; i < ROM.NLEN; i++) { d.w[ROM.NLEN + i] += d.muladd(d.w[i], ROM.MConst - 1, d.w[i], ROM.NLEN + i - 1); } b = new BIG(0); for (int i = 0; i < ROM.NLEN; i++) { b.w[i] = d.w[ROM.NLEN + i]; } b.norm(); } if (ROM.MODTYPE == ROM.NOT_SPECIAL) { BIG md = new BIG(ROM.Modulus); long m, carry; for (int i = 0; i < ROM.NLEN; i++) { if (ROM.MConst == -1) { m = (-d.w[i]) & ROM.MASK; } else { if (ROM.MConst == 1) { m = d.w[i]; } else { m = (ROM.MConst * d.w[i]) & ROM.MASK; } } carry = 0; for (int j = 0; j < ROM.NLEN; j++) { carry = d.muladd(m, md.w[j], carry, i + j); } d.w[ROM.NLEN + i] += carry; } b = new BIG(0); for (int i = 0; i < ROM.NLEN; i++) { b.w[i] = d.w[ROM.NLEN + i]; } b.norm(); } return(b); }
/* this=1/this mod p. Binary method */ public virtual void invmodp(BIG p) { mod(p); BIG u = new BIG(this); BIG v = new BIG(p); BIG x1 = new BIG(1); BIG x2 = new BIG(0); BIG t = new BIG(0); BIG one = new BIG(1); while (comp(u, one) != 0 && comp(v, one) != 0) { while (u.parity() == 0) { u.shr(1); if (x1.parity() != 0) { x1.add(p); x1.norm(); } x1.shr(1); } while (v.parity() == 0) { v.shr(1); if (x2.parity() != 0) { x2.add(p); x2.norm(); } x2.shr(1); } if (comp(u, v) >= 0) { u.sub(v); u.norm(); if (comp(x1, x2) >= 0) { x1.sub(x2); } else { t.copy(p); t.sub(x2); x1.add(t); } x1.norm(); } else { v.sub(u); v.norm(); if (comp(x2, x1) >= 0) { x2.sub(x1); } else { t.copy(p); t.sub(x1); x2.add(t); } x2.norm(); } } if (comp(u, one) == 0) { copy(x1); } else { copy(x2); } }
/* 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=q0^u0.q1^u1.q2^u2.q3^u3 */ /* Timing attack secure, but not cache attack secure */ public static FP12 pow4(FP12[] q, BIG[] u) { int i, j, nb, m; int[] a = new int[4]; FP12[] g = new FP12[8]; FP12[] s = new FP12[2]; FP12 c = new FP12(1); FP12 p = new FP12(0); BIG[] t = new BIG[4]; BIG mt = new BIG(0); sbyte[] w = new sbyte[ROM.NLEN * ROM.BASEBITS + 1]; for (i = 0; i < 4; i++) { t[i] = new BIG(u[i]); } s[0] = new FP12(0); s[1] = new FP12(0); g[0] = new FP12(q[0]); s[0].copy(q[1]); s[0].conj(); g[0].mul(s[0]); g[1] = new FP12(g[0]); g[2] = new FP12(g[0]); g[3] = new FP12(g[0]); g[4] = new FP12(q[0]); g[4].mul(q[1]); g[5] = new FP12(g[4]); g[6] = new FP12(g[4]); g[7] = new FP12(g[4]); s[1].copy(q[2]); s[0].copy(q[3]); s[0].conj(); s[1].mul(s[0]); s[0].copy(s[1]); s[0].conj(); g[1].mul(s[0]); g[2].mul(s[1]); g[5].mul(s[0]); g[6].mul(s[1]); s[1].copy(q[2]); s[1].mul(q[3]); s[0].copy(s[1]); s[0].conj(); g[0].mul(s[0]); g[3].mul(s[1]); g[4].mul(s[0]); g[7].mul(s[1]); /* if power is even add 1 to power, and add q to correction */ for (i = 0; i < 4; i++) { if (t[i].parity() == 0) { t[i].inc(1); t[i].norm(); c.mul(q[i]); } mt.add(t[i]); mt.norm(); } c.conj(); 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] = (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(g[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { m = w[i] >> 7; j = (w[i] ^ m) - m; // j=abs(w[i]) j = (j - 1) / 2; s[0].copy(g[j]); s[1].copy(g[j]); s[1].conj(); p.usqr(); p.mul(s[m & 1]); } p.mul(c); // apply correction p.reduce(); return(p); }
/* normalise this */ public void norm() { x.norm(); }
/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */ public FP4 xtr_pow2(FP4 ck, FP4 ckml, FP4 ckm2l, BIG a, BIG b) { a.norm(); b.norm(); BIG e = new BIG(a); BIG d = new BIG(b); BIG w = new BIG(0); FP4 cu = new FP4(ck); // can probably be passed in w/o copying FP4 cv = new FP4(this); FP4 cumv = new FP4(ckml); FP4 cum2v = new FP4(ckm2l); FP4 r = new FP4(0); FP4 t = new FP4(0); int f2 = 0; while (d.parity() == 0 && e.parity() == 0) { d.fshr(1); e.fshr(1); f2++; } while (BIG.comp(d, e) != 0) { if (BIG.comp(d, e) > 0) { w.copy(e); w.imul(4); w.norm(); if (BIG.comp(d, w) <= 0) { w.copy(d); d.copy(e); e.rsub(w); e.norm(); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cum2v.copy(cumv); cum2v.conj(); cumv.copy(cv); cv.copy(cu); cu.copy(t); } else if (d.parity() == 0) { d.fshr(1); r.copy(cum2v); r.conj(); t.copy(cumv); t.xtr_A(cu, cv, r); cum2v.copy(cumv); cum2v.xtr_D(); cumv.copy(t); cu.xtr_D(); } else if (e.parity() == 1) { d.sub(e); d.norm(); d.fshr(1); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cu.xtr_D(); cum2v.copy(cv); cum2v.xtr_D(); cum2v.conj(); cv.copy(t); } else { w.copy(d); d.copy(e); d.fshr(1); e.copy(w); t.copy(cumv); t.xtr_D(); cumv.copy(cum2v); cumv.conj(); cum2v.copy(t); cum2v.conj(); t.copy(cv); t.xtr_D(); cv.copy(cu); cu.copy(t); } } if (BIG.comp(d, e) < 0) { w.copy(d); w.imul(4); w.norm(); if (BIG.comp(e, w) <= 0) { e.sub(d); e.norm(); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cum2v.copy(cumv); cumv.copy(cu); cu.copy(t); } else if (e.parity() == 0) { w.copy(d); d.copy(e); d.fshr(1); e.copy(w); t.copy(cumv); t.xtr_D(); cumv.copy(cum2v); cumv.conj(); cum2v.copy(t); cum2v.conj(); t.copy(cv); t.xtr_D(); cv.copy(cu); cu.copy(t); } else if (d.parity() == 1) { w.copy(e); e.copy(d); w.sub(d); w.norm(); d.copy(w); d.fshr(1); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cumv.conj(); cum2v.copy(cu); cum2v.xtr_D(); cum2v.conj(); cu.copy(cv); cu.xtr_D(); cv.copy(t); } else { d.fshr(1); r.copy(cum2v); r.conj(); t.copy(cumv); t.xtr_A(cu, cv, r); cum2v.copy(cumv); cum2v.xtr_D(); cumv.copy(t); cu.xtr_D(); } } } r.copy(cv); r.xtr_A(cu, cumv, cum2v); for (int i = 0; i < f2; i++) { r.xtr_D(); } r = r.xtr_pow(d); return(r); }