/* * Completely rewritten in CryptKit-18, 13 Jan 1997, for new IEEE-style * curveParameters. */ int which_curve(giant x, curveParams *par) /* Returns (+-1) depending on whether x is on curve (+-)y^2 = x^3 + c x^2 + a x + b. */ { giant t1; giant t2; giant t3; int result; PROF_START; t1 = borrowGiant(par->maxDigits); t2 = borrowGiant(par->maxDigits); t3 = borrowGiant(par->maxDigits); /* First, set t2:= x^3 + c x^2 + a x + b. */ gtog(x, t2); addg(par->c, t2); mulg(x, t2); addg(par->a, t2); /* t2 := x^2 + c x + a. */ feemod(par, t2); mulg(x, t2); addg(par->b, t2); feemod(par, t2); /* Next, test whether t2 is a square. */ gtog(t2, t1); make_base(par, t3); iaddg(1, t3); gshiftright(1, t3); /* t3 = (p+1)/2. */ feepowermodg(par, t1, t3); /* t1 := t2^((p+1)/2) (mod p). */ if(gcompg(t1, t2) == 0) result = CURVE_PLUS; else result = CURVE_MINUS; returnGiant(t1); returnGiant(t2); returnGiant(t3); PROF_END(whichCurveTime); return result; }
void gmersennemod( int n, giant g ) /* g := g (mod 2^n - 1) */ { int the_sign; giant scratch3 = borrowGiant(g->capacity); giant scratch4 = borrowGiant(1); if ((the_sign = gsign(g)) < 0) absg(g); while (bitlen(g) > n) { gtog(g,scratch3); gshiftright(n,scratch3); addg(scratch3,g); gshiftleft(n,scratch3); subg(scratch3,g); } if(isZero(g)) goto out; int_to_giant(1,scratch3); gshiftleft(n,scratch3); int_to_giant(1,scratch4); subg(scratch4,scratch3); if(gcompg(g,scratch3) >= 0) subg(scratch3,g); if (the_sign < 0) { g->sign = -g->sign; addg(scratch3,g); } out: returnGiant(scratch3); returnGiant(scratch4); }
main(int argc, char **argv) { giant p = newgiant(CM_SHORTS); giant u = newgiant(CM_SHORTS); giant v = newgiant(CM_SHORTS); giant g[6]; giant plus_order = newgiant(CM_SHORTS); giant minus_order = newgiant(CM_SHORTS); giant a = newgiant(CM_SHORTS); giant b = newgiant(CM_SHORTS); int d, dc, olen, k; init_tools(CM_SHORTS); /* Basic algorithms. */ printf("Give base prime p:\n"); fflush(stdout); gin(p); for(dc=0; dc < 6; dc++) g[dc] = newgiant(CM_SHORTS); for(dc = 0; dc < DCOUNT; dc++) { d = disc12[dc]; /* Next, seek representation 4N = u^2 + |d| v^2. */ if(cornacchia4(p, d, u, v) == 0) continue; /* Here, (u,v) give the quadratic representation of 4p. */ printf("D: %d\n", d); fflush(stdout); gtog(u, g[0]); switch(d) { case -3: olen = 3; /* Six orders: p + 1 +- g[0,1,2]. */ gtog(u, g[1]); gtog(v, g[2]); addg(g[2], g[2]); addg(v, g[2]); /* g[2] := 3v. */ addg(g[2], g[1]); gshiftright(1, g[1]); /* g[1] = (u + 3v)/2. */ subg(u, g[2]); gshiftright(1, g[2]); absg(g[2]); /* g[2] = |u-3v|/2. */ break; case -4: olen = 2; /* Four orders: p + 1 +- g[0,1]. */ gtog(v, g[1]); addg(g[1], g[1]); /* g[1] = 2v. */ break; default: olen = 1; /* Two orders: p + 1 +- g[0]. */ } for(k=0; k < olen; k++) { gtog(p, plus_order); iaddg(1, plus_order); gtog(p, minus_order); iaddg(1, minus_order); addg(g[k], plus_order); subg(g[k], minus_order); printf("curve orders: \n"); printf("(%d) ", prime_probable(plus_order)); gout(plus_order); printf("(%d) ", prime_probable(minus_order)); gout(minus_order); } } }
void make_recip(giant d, giant r) /* r becomes the steady-state reciprocal * 2^(2b)/d, where b = bit-length of d-1. */ { int b; giant tmp, tmp2; if (isZero(d) || (d->sign < 0)) { exit(SIGN); } tmp = popg(); tmp2 = popg(); itog(1, r); subg(r, d); b = bitlen(d); addg(r, d); gshiftleft(b, r); gtog(r, tmp2); while (1) { gtog(r, tmp); squareg(tmp); gshiftright(b, tmp); mulg(d, tmp); gshiftright(b, tmp); addg(r, r); subg(tmp, r); if (gcompg(r, tmp2) <= 0) break; gtog(r, tmp2); } itog(1, tmp); gshiftleft(2 * b, tmp); gtog(r, tmp2); mulg(d, tmp2); subg(tmp2, tmp); itog(1, tmp2); while (tmp->sign < 0) { subg(tmp2, r); addg(d, tmp); } pushg(2); }
void modg_via_recip(giant d, giant r, giant n) /* This is the fastest mod of the present collection. * n := n % d, where r is the precalculated * steady-state reciprocal of d. */ { int s = (bitlen(r) - 1), sign = n->sign; giant tmp, tmp2; if (isZero(d) || (d->sign < 0)) { exit(SIGN); } tmp = popg(); tmp2 = popg(); n->sign = abs(n->sign); while (1) { gtog(n, tmp); gshiftright(s - 1, tmp); mulg(r, tmp); gshiftright(s + 1, tmp); mulg(d, tmp); subg(tmp, n); if (gcompg(n, d) >= 0) subg(d, n); if (gcompg(n, d) < 0) break; } if (sign >= 0) goto done; if (isZero(n)) goto done; negg(n); addg(d, n); done: pushg(2); return; }
void gshiftleft(int bits, giant g) /* shift g left bits bits. Equivalent to g = g*2^bits. */ { int rem = bits & 15, crem = 16 - rem, words = bits >> 4; int size = abs(g->sign), j, k, sign = gsign(g); unsigned short carry, dat; if (!bits) return; if (!size) return; if (bits < 0) { gshiftright(-bits, g); return; } if (size + words + 1 > current_max_size) { error = OVFLOW; exit(error); } if (rem == 0) { memmove(g->n + words, g->n, size * sizeof(short)); for (j = 0; j < words; j++) g->n[j] = 0; g->sign += (g->sign < 0) ? (-words) : (words); } else { k = size + words; carry = 0; for (j = size - 1; j >= 0; j--) { dat = g->n[j]; g->n[k--] = (unsigned short)((dat >> crem) | carry); carry = (unsigned short)(dat << rem); } do { g->n[k--] = carry; carry = 0; } while (k >= 0); k = size + words; if (g->n[k] == 0) --k; g->sign = sign * (k + 1); } }
static int jacobi_symbol(giant a, curveParams *cp) /* Standard Jacobi symbol (a/cp->basePrime). basePrime must be odd, positive. */ { int t = 1, u; giant t5 = borrowGiant(cp->maxDigits); giant t6 = borrowGiant(cp->maxDigits); giant t7 = borrowGiant(cp->maxDigits); int rtn; gtog(a, t5); feemod(cp, t5); gtog(cp->basePrime, t6); while(!isZero(t5)) { u = (t6->n[0]) & 7; while((t5->n[0] & 1) == 0) { gshiftright(1, t5); if((u==3) || (u==5)) t = -t; } gtog(t5, t7); gtog(t6, t5); gtog(t7, t6); u = (t6->n[0]) & 3; if(((t5->n[0] & 3) == 3) && ((u & 3) == 3)) t = -t; modg(t6, t5); } if(isone(t6)) { rtn = t; } else { rtn = 0; } returnGiant(t5); returnGiant(t6); returnGiant(t7); return rtn; }
static int sqrtmod(giant x, curveParams *cp) /* If Sqrt[x] (mod p) exists, function returns 1, else 0. In either case x is modified, but if 1 is returned, x:= Sqrt[x] (mod p). */ { int rtn; giant t0 = borrowGiant(cp->maxDigits); giant t1 = borrowGiant(cp->maxDigits); giant t2 = borrowGiant(cp->maxDigits); giant t3 = borrowGiant(cp->maxDigits); giant t4 = borrowGiant(cp->maxDigits); giant p = cp->basePrime; feemod(cp, x); /* Justify the argument. */ gtog(x, t0); /* Store x for eventual validity check on square root. */ if((p->n[0] & 3) == 3) { /* The case p = 3 (mod 4). */ gtog(p, t1); iaddg(1, t1); gshiftright(2, t1); powermodg(x, t1, cp); goto resolve; } /* Next, handle case p = 5 (mod 8). */ if((p->n[0] & 7) == 5) { gtog(p, t1); int_to_giant(1, t2); subg(t2, t1); gshiftright(2, t1); gtog(x, t2); powermodg(t2, t1, cp); /* t2 := x^((p-1)/4) % p. */ iaddg(1, t1); gshiftright(1, t1); /* t1 := (p+3)/8. */ if(isone(t2)) { powermodg(x, t1, cp); /* x^((p+3)/8) is root. */ goto resolve; } else { int_to_giant(1, t2); subg(t2, t1); /* t1 := (p-5)/8. */ gshiftleft(2,x); powermodg(x, t1, cp); mulg(t0, x); addg(x, x); feemod(cp, x); /* 2x (4x)^((p-5)/8. */ goto resolve; } } /* Next, handle tougher case: p = 1 (mod 8). */ int_to_giant(2, t1); while(1) { /* Find appropriate nonresidue. */ gtog(t1, t2); gsquare(t2); subg(x, t2); feemod(cp, t2); if(jacobi_symbol(t2, cp) == -1) break; iaddg(1, t1); } /* t2 is now w^2 in F_p^2. */ int_to_giant(1, t3); gtog(p, t4); iaddg(1, t4); gshiftright(1, t4); powFp2(t1, t3, t2, t4, cp); gtog(t1, x); resolve: gtog(x,t1); gsquare(t1); feemod(cp, t1); if(gcompg(t0, t1) == 0) { rtn = 1; /* Success. */ } else { rtn = 0; /* no square root */ } returnGiant(t0); returnGiant(t1); returnGiant(t2); returnGiant(t3); returnGiant(t4); return rtn; }
void ellAddProj(pointProj pt0, pointProj pt1, curveParams *cp) /* pt0 := pt0 + pt1 on the curve. */ { giant x0 = pt0->x, y0 = pt0->y, z0 = pt0->z, x1 = pt1->x, y1 = pt1->y, z1 = pt1->z; giant t1; giant t2; giant t3; giant t4; giant t5; giant t6; giant t7; if(isZero(z0)) { gtog(x1,x0); gtog(y1,y0); gtog(z1,z0); return; } if(isZero(z1)) return; t1 = borrowGiant(cp->maxDigits); t2 = borrowGiant(cp->maxDigits); t3 = borrowGiant(cp->maxDigits); t4 = borrowGiant(cp->maxDigits); t5 = borrowGiant(cp->maxDigits); t6 = borrowGiant(cp->maxDigits); t7 = borrowGiant(cp->maxDigits); gtog(x0, t1); gtog(y0,t2); gtog(z0, t3); gtog(x1, t4); gtog(y1, t5); if(!isone(z1)) { gtog(z1, t6); gtog(t6, t7); gsquare(t7); feemod(cp, t7); mulg(t7, t1); feemod(cp, t1); mulg(t6, t7); feemod(cp, t7); mulg(t7, t2); feemod(cp, t2); } gtog(t3, t7); gsquare(t7); feemod(cp, t7); mulg(t7, t4); feemod(cp, t4); mulg(t3, t7); feemod(cp, t7); mulg(t7, t5); feemod(cp, t5); negg(t4); addg(t1, t4); feemod(cp, t4); negg(t5); addg(t2, t5); feemod(cp, t5); if(isZero(t4)) { if(isZero(t5)) { ellDoubleProj(pt0, cp); } else { int_to_giant(1, x0); int_to_giant(1, y0); int_to_giant(0, z0); } goto out; } addg(t1, t1); subg(t4, t1); feemod(cp, t1); addg(t2, t2); subg(t5, t2); feemod(cp, t2); if(!isone(z1)) { mulg(t6, t3); feemod(cp, t3); } mulg(t4, t3); feemod(cp, t3); gtog(t4, t7); gsquare(t7); feemod(cp, t7); mulg(t7, t4); feemod(cp, t4); mulg(t1, t7); feemod(cp, t7); gtog(t5, t1); gsquare(t1); feemod(cp, t1); subg(t7, t1); feemod(cp, t1); subg(t1, t7); subg(t1, t7); feemod(cp, t7); mulg(t7, t5); feemod(cp, t5); mulg(t2, t4); feemod(cp, t4); gtog(t5, t2); subg(t4,t2); feemod(cp, t2); if(t2->n[0] & 1) { /* Test if t2 is odd. */ addg(cp->basePrime, t2); } gshiftright(1, t2); gtog(t1, x0); gtog(t2, y0); gtog(t3, z0); out: returnGiant(t1); returnGiant(t2); returnGiant(t3); returnGiant(t4); returnGiant(t5); returnGiant(t6); returnGiant(t7); }
feeReturn feeECDSAVerify(const unsigned char *sigData, size_t sigDataLen, const unsigned char *data, unsigned dataLen, feePubKey pubKey, feeSigFormat format) { /* giant integers per IEEE P1363 notation */ giant h; // s^(-1) giant h1; // f h giant h2; // c times h giant littleC; // newGiant from ECDSA_decode giant littleD; // ditto giant c; // borrowed, full size giant d; // ditto giant cPrime = NULL; // i mod r pointProj h1G = NULL; // h1 'o' G pointProj h2W = NULL; // h2 'o' W key W; // i.e., their public key unsigned version; feeReturn frtn; curveParams *cp = feePubKeyCurveParams(pubKey); unsigned groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); int result; if(cp == NULL) { return FR_BadPubKey; } /* * First decode the byteRep string. */ frtn = ECDSA_decode( format, groupBytesLen, sigData, sigDataLen, &littleC, &littleD, &version); if(frtn) { return frtn; } /* * littleC and littleD have capacity = abs(sign), probably * not big enough.... */ c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); gtog(littleC, c); gtog(littleD, d); freeGiant(littleC); freeGiant(littleD); sigDbg(("ECDSA verify:\n")); /* * Verify that c and d are within [1,group_order-1] */ if((gcompg(cp->cOrderPlus, c) != 1) || (gcompg(cp->cOrderPlus, d) != 1) || isZero(c) || isZero(d)) { returnGiant(c); returnGiant(d); return FR_InvalidSignature; } /* * W = signer's public key */ W = feePubKeyPlusCurve(pubKey); /* * 1) Compute h = d^(-1) (mod x1OrderPlus); */ SIGPROF_START; h = borrowGiant(cp->maxDigits); gtog(d, h); binvg_x1OrderPlus(cp, h); SIGPROF_END(vfyStep1); /* * 2) h1 = digest as giant (skips assigning to 'f' in P1363) */ if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { h1 = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { h1 = borrowGiant(cp->maxDigits); } deserializeGiant(data, h1, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, h1); } sigLogGiant(" Wx : ", W->x); sigLogGiant(" f : ", h1); sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); sigLogGiant(" s^(-1) : ", h); /* * 3) Compute h1 = f * h mod x1OrderPlus; */ SIGPROF_START; mulg(h, h1); // h1 := f * h x1OrderPlusMod(h1, cp); SIGPROF_END(vfyStep3); /* * 4) Compute h2 = c * h (mod x1OrderPlus); */ SIGPROF_START; h2 = borrowGiant(cp->maxDigits); gtog(c, h2); mulg(h, h2); // h2 := c * h x1OrderPlusMod(h2, cp); SIGPROF_END(vfyStep4); /* * 5) Compute h2W = h2 'o' W (W = theirPub) */ CKASSERT((W->y != NULL) && !isZero(W->y)); h2W = newPointProj(cp->maxDigits); gtog(W->x, h2W->x); gtog(W->y, h2W->y); int_to_giant(1, h2W->z); ellMulProjSimple(h2W, h2, cp); /* * 6) Compute h1G = h1 'o' G (G = {x1Plus, y1Plus, 1} ) */ CKASSERT((cp->y1Plus != NULL) && !isZero(cp->y1Plus)); h1G = newPointProj(cp->maxDigits); gtog(cp->x1Plus, h1G->x); gtog(cp->y1Plus, h1G->y); int_to_giant(1, h1G->z); ellMulProjSimple(h1G, h1, cp); /* * 7) h1G := (h1 'o' G) + (h2 'o' W) */ ellAddProj(h1G, h2W, cp); /* * 8) If elliptic sum is point at infinity, signature is bad; stop. */ if(isZero(h1G->z)) { dbgLog(("feeECDSAVerify: h1 * G = point at infinity\n")); result = 1; goto vfyDone; } normalizeProj(h1G, cp); /* * 9) cPrime = x coordinate of elliptic sum, mod x1OrderPlus */ cPrime = borrowGiant(cp->maxDigits); gtog(h1G->x, cPrime); x1OrderPlusMod(cPrime, cp); /* * 10) Good sig iff cPrime == c */ result = gcompg(c, cPrime); vfyDone: if(result) { frtn = FR_InvalidSignature; #if LOG_BAD_SIG printf("***yup, bad sig***\n"); #endif // LOG_BAD_SIG } else { frtn = FR_Success; } returnGiant(c); returnGiant(d); returnGiant(h); returnGiant(h1); returnGiant(h2); if(h1G != NULL) { freePointProj(h1G); } if(h2W != NULL) { freePointProj(h2W); } if(cPrime != NULL) { returnGiant(cPrime); } return frtn; }
feeReturn feeECDSASign( feePubKey pubKey, feeSigFormat format, // Signature format DER 9.62 / RAW const unsigned char *data, // data to be signed unsigned dataLen, // in bytes feeRandFcn randFcn, // optional void *randRef, // optional unsigned char **sigData, // malloc'd and RETURNED unsigned *sigDataLen) // RETURNED { curveParams *cp; /* giant integers per IEEE P1363 notation */ giant c; // both 1363 'c' and 'i' // i.e., x-coord of u's pub key giant d; giant u; // random private key giant s; // private key as giant giant f; // data (message) as giant feeReturn frtn = FR_Success; feeRand frand; unsigned char *randBytes; unsigned randBytesLen; unsigned groupBytesLen; giant privGiant; #if ECDSA_SIGN_USE_PROJ pointProjStruct pt; // pt->x = c giant pty; // pt->y giant ptz; // pt->z #endif // ECDSA_SIGN_USE_PROJ if(pubKey == NULL) { return FR_BadPubKey; } cp = feePubKeyCurveParams(pubKey); if(cp == NULL) { return FR_BadPubKey; } if(cp->curveType != FCT_Weierstrass) { return FR_IllegalCurve; } CKASSERT(!isZero(cp->x1OrderPlus)); /* * Private key and message to be signed as giants */ privGiant = feePubKeyPrivData(pubKey); if(privGiant == NULL) { dbgLog(("Attempt to Sign without private data\n")); return FR_IllegalArg; } s = borrowGiant(cp->maxDigits); gtog(privGiant, s); if(dataLen > (cp->maxDigits * GIANT_BYTES_PER_DIGIT)) { f = borrowGiant(BYTES_TO_GIANT_DIGITS(dataLen)); } else { f = borrowGiant(cp->maxDigits); } deserializeGiant(data, f, dataLen); /* * Certicom SEC1 states that if the digest is larger than the modulus, * use the left q bits of the digest. */ unsigned hashBits = dataLen * 8; if(hashBits > cp->q) { gshiftright(hashBits - cp->q, f); } sigDbg(("ECDSA sign:\n")); sigLogGiant(" s : ", s); sigLogGiant(" f : ", f); c = borrowGiant(cp->maxDigits); d = borrowGiant(cp->maxDigits); u = borrowGiant(cp->maxDigits); if(randFcn == NULL) { frand = feeRandAlloc(); } else { frand = NULL; } /* * Random size is just larger than base prime */ groupBytesLen = ((feePubKeyBitsize(pubKey)+7) / 8); randBytesLen = groupBytesLen+8; // +8bytes (64bits) to reduce the biais when with reduction mod prime. Per FIPS186-4 - "Using Extra Random Bits" randBytes = (unsigned char*) fmalloc(randBytesLen); #if ECDSA_SIGN_USE_PROJ /* quick temp pointProj */ pty = borrowGiant(cp->maxDigits); ptz = borrowGiant(cp->maxDigits); pt.x = c; pt.y = pty; pt.z = ptz; #endif // ECDSA_SIGN_USE_PROJ while(1) { /* Repeat this loop until we have a non-zero c and d */ /* * 1) Obtain random u in [2, x1OrderPlus-2] */ SIGPROF_START; if(randFcn) { randFcn(randRef, randBytes, randBytesLen); } else { feeRandBytes(frand, randBytes, randBytesLen); } deserializeGiant(randBytes, u, randBytesLen); sigLogGiant(" raw u : ", u); sigLogGiant(" order : ", cp->x1OrderPlus); x1OrderPlusJustify(u, cp); SIGPROF_END(signStep1); sigLogGiant(" in range u : ", u); /* * note 'o' indicates elliptic multiply, * is integer mult. * * 2) Compute x coordinate, call it c, of u 'o' G * 3) Reduce: c := c mod x1OrderPlus; * 4) If c == 0, goto (1); */ SIGPROF_START; gtog(cp->x1Plus, c); #if ECDSA_SIGN_USE_PROJ /* projective coordinates */ gtog(cp->y1Plus, pty); int_to_giant(1, ptz); ellMulProjSimple(&pt, u, cp); #else /* ECDSA_SIGN_USE_PROJ */ /* the FEE way */ elliptic_simple(c, u, cp); #endif /* ECDSA_SIGN_USE_PROJ */ SIGPROF_END(signStep2); SIGPROF_START; x1OrderPlusMod(c, cp); SIGPROF_END(signStep34); if(isZero(c)) { dbgLog(("feeECDSASign: zero modulo (1)\n")); continue; } /* * 5) Compute u^(-1) mod x1OrderPlus; */ SIGPROF_START; gtog(u, d); binvg_x1OrderPlus(cp, d); SIGPROF_END(signStep5); sigLogGiant(" u^(-1) : ", d); /* * 6) Compute signature d as: * d = [u^(-1) (f + s*c)] (mod x1OrderPlus) */ SIGPROF_START; mulg(c, s); // s *= c x1OrderPlusMod(s, cp); addg(f, s); // s := f + (s * c) x1OrderPlusMod(s, cp); mulg(s, d); // d := u^(-1) (f + (s * c)) x1OrderPlusMod(d, cp); SIGPROF_END(signStep67); /* * 7) If d = 0, goto (1); */ if(isZero(d)) { dbgLog(("feeECDSASign: zero modulo (2)\n")); continue; } sigLogGiant(" c : ", c); sigLogGiant(" d : ", d); break; // normal successful exit } /* * 8) signature is now the integer pair (c, d). */ /* * Cook up raw data representing the signature. */ SIGPROF_START; ECDSA_encode(format,groupBytesLen, c, d, sigData, sigDataLen); SIGPROF_END(signStep8); if(frand != NULL) { feeRandFree(frand); } ffree(randBytes); returnGiant(u); returnGiant(d); returnGiant(c); returnGiant(f); returnGiant(s); #if ECDSA_SIGN_USE_PROJ returnGiant(pty); returnGiant(ptz); #endif /* ECDSA_SIGN_USE_PROJ */ return frtn; }
/* * Completely rewritten in CryptKit-18, 13 Jan 1997, for new IEEE-style * curveParameters. */ void elliptic_add(giant x1, giant x2, giant x3, curveParams *par, int s) { /* Addition algorithm for x3 = x1 + x2 on the curve, with sign ambiguity s. From theory, we know that if {x1,1} and {x2,1} are on a curve, then their elliptic sum (x1,1} + {x2,1} = {x3,1} must have x3 as one of two values: x3 = U/2 + s*Sqrt[U^2/4 - V] where sign s = +-1, and U,V are functions of x1,x2. Tho present function is called a maximum of twice, to settle which of +- is s. When a call is made, it is guaranteed already that x1, x2 both lie on the same curve (+- curve); i.e., which curve (+-) is not connected at all with sign s of the x3 relation. */ giant cur_n; giant t1; giant t2; giant t3; giant t4; giant t5; PROF_START; cur_n = borrowGiant(par->maxDigits); t1 = borrowGiant(par->maxDigits); t2 = borrowGiant(par->maxDigits); t3 = borrowGiant(par->maxDigits); t4 = borrowGiant(par->maxDigits); t5 = borrowGiant(par->maxDigits); if(gcompg(x1, x2)==0) { int_to_giant(1, t1); numer_double(x1, t1, x3, par); denom_double(x1, t1, t2, par); binvg_cp(par, t2); mulg(t2, x3); feemod(par, x3); goto out; } numer_plus(x1, x2, t1, par); int_to_giant(1, t3); numer_times(x1, t3, x2, t3, t2, par); int_to_giant(1, t4); int_to_giant(1, t5); denom_times(x1, t4, x2, t5, t3, par); binvg_cp(par, t3); mulg(t3, t1); feemod(par, t1); /* t1 := U/2. */ mulg(t3, t2); feemod(par, t2); /* t2 := V. */ /* Now x3 will be t1 +- Sqrt[t1^2 - t2]. */ gtog(t1, t4); gsquare(t4); feemod(par, t4); subg(t2, t4); make_base(par, cur_n); iaddg(1, cur_n); gshiftright(2, cur_n); /* cur_n := (p+1)/4. */ feepowermodg(par, t4, cur_n); /* t4 := t2^((p+1)/4) (mod p). */ gtog(t1, x3); if(s != SIGN_PLUS) negg(t4); addg(t4, x3); feemod(par, x3); out: returnGiant(cur_n); returnGiant(t1); returnGiant(t2); returnGiant(t3); returnGiant(t4); returnGiant(t5); PROF_END(ellAddTime); }